01 A registry is a production trust boundary
An Artifactory administrator controls a distribution system that other systems rely on. That is a serious foothold. It is not automatically an OpenShift cluster-admin identity: the downstream outcome depends on publishing permissions, artifact verification, deployment references and workload authority.
Separate the vulnerability from the attack path. A vulnerable version establishes exposure. An unauthorized administrative action establishes a different fact. A compromised registry feeding a production workload requires another chain of evidence entirely.
Registry authority, artifact trust and workload identity are different boundaries. Prove each transition; do not substitute a severity score for the chain.
02 Two entry routes, not three mandatory steps
JFrog's advisories describe three distinct flaws. CVE-2026-42018 exposes an internal anonymous token; CVE-2026-42016 concerns insufficient token validation; CVE-2026-82329 is an authentication bypass. Wiz reports active exploitation of the first two together and of the third separately. JFrog advisories · Wiz investigation.
| Route | Boundary under test | Evidence needed in your environment |
|---|---|---|
| 42018 → 42016 | Anonymous token issuance → intended token scope | Correlate issuance, identity and subsequent accepted privileged operations. Do not collect raw tokens. |
| 82329 | Unauthenticated requester → administrative authority | Correlate unexpected join activity with account, configuration or token-management changes. |
| Downstream supply chain | Registry write access → accepted production artifact | Match the changed digest to the actual running workload and its admission decision. |
03 Interactive investigation map
Expand a branch to see the question, supporting evidence and control that breaks that part of the path. This is an investigation model, not an exploitation console.
Identity & authority
Who gained authority?
Compare the effective privileges with the account's approved purpose. Retain token identifiers and scope metadata, not bearer credentials. An anonymous subject name must not be treated as evidence of low privilege.
What authorized the action?
Join access logs to account changes and the identity provider's timeline. Identify whether the action matched an approved administrative workflow. Break the path with supported patches, restricted administrative reachability and narrow machine identities.
Artifacts & provenance
What changed?
Compare digests, repository configuration and plugin hashes against an independently preserved baseline. A hash obtained only from the suspect registry is not an independent integrity check.
Who consumed it?
Follow the artifact through publishing, promotion and deployment. Resolve mutable tags to the digest the runtime actually pulled. Break the path with protected promotion, digest pinning and enforced provenance from a trusted signer.
Execution & containment
Which identity ran it?
Record the pod, namespace, ServiceAccount, node and relevant RBAC edges. Assess that workload's effective authority. A registry administrator and a Kubernetes administrator are not interchangeable identities.
What stops recurrence?
Separate containment from recovery. Preserve evidence, restrict affected distribution paths, and rotate exposed credentials from a trusted system. Validate that the corrected admission and authorization controls reject the demonstrated path.
04 Reconstruct the downstream path
Analysis scenario: an attacker changes an artifact that a production pipeline is allowed to consume. Each arrow below represents a transition that must be demonstrated; none is guaranteed by Artifactory administrative access alone.
- 1 · Registry changeIdentity, repository, time, prior and new digest.
- 2 · PromotionBuild identity, approval and destination repository.
- 3 · AdmissionResolved digest, signer, policy decision and deployment revision.
- 4 · WorkloadRuntime imageID, ServiceAccount, RBAC and observed behavior.
05 The Read-Only Investigation Runbook
Patching stops step 1 tomorrow. It does nothing about the admin account created last week or the Groovy plugin already on disk. Run two parallel investigations: a compromise hunt (did someone get in, mint tokens, plant plugins, alter artifacts?) and a posture review (could a build system or upstream repo still poison what OpenShift runs?).
Everything below is read-only and evidence-first. It uses an approved investigation identity and a protected curl config — never paste tokens into commands, screenshots, or chat. UI labels vary by version and license.
5.1 · Preserve evidence before you touch anything
Before you restart Artifactory, delete a suspicious account, clear a cache, or rotate a credential — capture state. Restarting rotates logs; deleting an account destroys the timeline.
5.2 · Establish version, exposure, and repository inventory
Use an approved investigation identity. Have your administrator provision a protected curl config holding the auth header — accessible only to its owner. Never use curl -k.
export ART_URL='https://artifactory.example.com/artifactory' export JFROG_CURL_CONFIG='/secure/path/artifactory-audit.curl' # header lives here, not on the CLI # Exact running build — compare against ALL THREE advisories, not one headline CVE curl --fail --silent --show-error --config "$JFROG_CURL_CONFIG" \ "$ART_URL/api/system/version" # Full repository inventory — Local, Remote, Virtual, Federated curl --fail --silent --show-error --config "$JFROG_CURL_CONFIG" \ "$ART_URL/api/repositories"
Read the version output: record version, revision, deployment type, and the date each node was patched. Then establish exposure — self-hosted or Cloud? VM, container, or OpenShift? Which UI/API/registry endpoints are internet-reachable? Can callers bypass the reverse proxy and hit backend services directly? Were vulnerable versions exposed before patching? In the inventory, look for unknown repositories, unexpected package types, dev repos serving production, and missing ownership. A restricted identity may not see everything — incomplete visibility is an assessment gap, not a pass.
5.3 · Hunt unexpected administrators and tokens
This is where the chain lands. In Administration → Identity and Access, review Users, Groups, Permissions, and Access Tokens against what you expect.
| Inspect | Expected | Investigate immediately |
|---|---|---|
| Administrators | Named, approved owners | Unknown account or unexplained elevation |
| Service accounts | One identity per integration/environment | A Jenkins or pull identity holding platform-admin |
| Tokens | Known subject, scope, issuer, audience, expiry | Admin scope on an anonymous subject; long lifetime; cross-instance audience |
| Groups | Approved membership | Unexpected privileged or broad auto-join membership |
| Federation / trust | Documented trusted instances | An undocumented trust relationship |
| Anonymous access | Deliberately restricted | Anonymous reaching private artifacts or privileged activity |
Token identities are not always persistent users, so reviewing the Users page alone is insufficient. For any suspicious identity, record the username/token ID, creation time, scope, and source IP — and correlate every one against the access log, IdP activity, and the expected owner. Do not export token values.
5.4 · Reconstruct the sequence from logs
Collect and work against preserved copies — not the live install. The files that matter: artifactory-access.log, artifactory-request.log, artifactory-service.log, the Access service logs, router-request.log, artifactory-request-out.log, and every rotated equivalent.
export EVIDENCE_DIR='/secure/evidence/artifactory-case' # The signature of this chain: privileged actions attributed to the anonymous token rg -n -i 'token:anonymous|/access/api/v1/aws/token' "$EVIDENCE_DIR" -g '*.log' # Identity / plugin / config activity to correlate rg -n -i '/security/users|/tokens|/groups|/permissions|/plugins|\.groovy' "$EVIDENCE_DIR" -g '*.log' # Security-relevant state changes rg -n -i 'CONFIGURATION_CHANGE|ACCEPTED (DEPLOY|DELETE)|BUILD_PROMOTE|PROPERTY_UPDATED' "$EVIDENCE_DIR" -g '*.log'
These are triage leads, not reliable signatures — they produce legitimate matches and do not search compressed archives (process those separately on working copies). Look for the ordered sequence: unexpected caller → token activity → admin creation/elevation → plugin/config change → unusual outbound connection or artifact modification. For each event, pin UTC timestamp, identity, source IP, trace ID, URL, and outcome. Behind a proxy, resolve the true client IP from trusted proxy logs — an HTTP 200 or an "anonymous" entry alone does not prove exploitation.
5.5 · Inspect plugins and host persistence
Malicious Groovy plugins and payloads in temp directories were the reported persistence mechanism. Treat those as hunting leads, against a preserved copy — do not execute or reload a suspicious plugin.
# Hash every plugin file and diff against your known-good Git repo / deployment package
find "$EVIDENCE_DIR/plugins" -maxdepth 3 -type f -exec sha256sum {} +
# If IR authorises live host triage — recent drops in the classic staging dirs
find /tmp /var/tmp /dev/shm -xdev -type f -newermt '2026-08-15' \
-printf '%TY-%Tm-%TdT%TH:%TM:%TS %u %s %p\n'
# Process ancestry and current listeners (visibility depends on permissions)
ps -eo user,pid,ppid,lstart,args --forest
ss -plant
Investigate unapproved .groovy files or dependency JARs, legitimate plugin names with changed content, and any plugin code that executes processes, opens network connections, or reads credential files. Timestamps can be forged and temp files are not inherently malicious — prefer EDR evidence for historical execution. For containerised or OpenShift deployments, investigate both the workload and its node / PVCs.
5.6 · Review remotes, mirrors, and Helm — and the artifacts themselves
A remote repository is an on-demand cache, not a full mirror; a normal request through it can fetch upstream and mutate the cache — so preserve metadata first and avoid exploratory downloads during forensics. For each remote/virtual/federated repo, inspect upstream URL and TLS, upstream credentials, virtual membership and deployment target, and replication direction.
| Control | Red flag |
|---|---|
| Upstream source URL | Unknown domain, plain HTTP, or an unexpected internal destination |
| TLS verification | Certificate validation bypassed |
| Virtual membership / ordering | Production resolves from a dev or untrusted remote |
| Replication / federation | Undocumented external synchronization |
| Environment separation | A dev identity can publish production artifacts |
Then hunt artifact tampering with a bounded, read-only AQL query — this is a POST that queries, not an upload:
curl --fail --silent --show-error --config "$JFROG_CURL_CONFIG" \
-H 'Content-Type: text/plain' --data-binary \
'items.find({"repo":"docker-prod-local","type":"file","modified":{"$gte":"2026-08-15T00:00:00Z"}})
.include("repo","path","name","created","created_by","modified","modified_by","size")
.sort({"$desc":["modified"]}).limit(100)' \
"$ART_URL/api/search/aql"
Investigate production modifications by humans or unexpected service accounts, changes outside release windows, missing build provenance, and — the one that ends careers — a previously approved tag now resolving to a different digest. AQL shows current metadata, not overwrite history; verify integrity against an independent trusted record. A checksum stored inside a compromised registry is not independent proof.
5.7 · Trace the blast radius into Jenkins, Argo CD, and OpenShift
For each suspicious artifact, walk the chain forward: artifact digest → publishing Jenkins build → source commit → promotion → Argo CD revision → deployed workload. Read what is actually running, not what Git says should be running.
oc --context=prod-cluster -n app-namespace get pod app-pod \
-o jsonpath='{range .status.containerStatuses[*]}{.name}{"\t"}{.image}{"\t"}{.imageID}{"\n"}{end}'
# init containers matter too — a poisoned init image escapes a main-container-only check
oc --context=prod-cluster -n app-namespace get pod app-pod \
-o jsonpath='{range .status.initContainerStatuses[*]}{.name}{"\t"}{.image}{"\t"}{.imageID}{"\n"}{end}'
image is the requested reference; imageID is the runtime-resolved digest. Then confirm: could Jenkins credentials publish directly to production? Could untrusted pull-request builds reach publishing credentials? Does production admission actually enforce signatures/provenance, or merely log? Argo CD "Synced" does not mean the image is trustworthy — a changed mutable tag leaves Git untouched.
06 Verdict — Config Finding Or Incident?
The evidence decides the response. Do not let "we patched" collapse into "we're clean."
| Evidence | Classification & next action |
|---|---|
| Vulnerable version, no corroborating activity | Exposure — prioritise patching, keep hunting |
| Excessive CI permissions or untrusted upstream | Posture finding — document the attack path and remediate |
| Unauthorised admin/token, or a malicious plugin | Incident — activate IR, assess privileged compromise |
| Unauthorised production artifact change | Supply-chain incident — identify and contain downstream consumers |
| Missing logs / incomplete visibility | Inconclusive — not "clean" |
If compromise is suspected: preserve evidence, restrict affected access and promotion routes, rotate exposed credentials from a trusted system, and handle JFrog trust/join-key changes through the vendor-supported recovery process. Deleting one plugin is not recovery. Record each finding as: UTC time | node/repo | identity | evidence ref | artifact digest | affected builds/workloads | severity | owner | next action.
07 Detection is correlation, not a path match
Use a short, documented correlation window and retain the underlying events. Group by trustworthy client address, identity and instance; include reverse-proxy records where they provide the only reliable caller attribution.
| Lead | Corroboration | False-positive check |
|---|---|---|
| Unexpected token or join activity | Privileged account or configuration change by the same actor | Was an approved administrative integration running? |
| Plugin integrity mismatch | Deployment provenance, file history and process telemetry | Was a reviewed plugin release deployed? |
| Production artifact modification | Independent digest, publishing identity and downstream imageID | Was the modification an approved promotion? |
These are detection design patterns, not tested vendor-neutral SIEM rules. Verify field mappings and retention in your own pipeline. Missing evidence should produce an inconclusive result, not a clean bill of health.
08 Break the demonstrated path
09 Final word
The hardest question is not whether the registry was vulnerable. It is whether authority crossed from that registry into a system you still consider trusted. Answer it with identities, digests and authorization decisions—not with a dashboard's green status.
Security teams own the reconstruction. Trace the actual path, identify the missing controls, and demonstrate that remediation breaks it.
— Riad DAHMANI, k8sec Security Research
Continue from infrastructure evidence.
K8SEC Agent provides read-only Kubernetes graph intelligence. Correlate its workload and identity relationships with separately collected registry and pipeline evidence; it does not autonomously exploit or validate this supply-chain scenario.
Explore KAOS methodology Read the detection engineering guideReferences: JFrog security advisories; Wiz's original investigation, updated September 11, 2026; CISA KEV catalog. Downstream examples and investigation tips are K8SEC analysis, not claims that every affected installation follows the same path. Validation is restricted to systems you are authorized to assess.
