Skip to content

fix(ci): select the qualified TruffleHog scanner image - #193

Merged
joshavant merged 1 commit into
mainfrom
security/emudhra-trufflehog-runtime-20261023
Oct 25, 2026
Merged

joshavant merged 1 commit into
mainfrom
security/emudhra-trufflehog-runtime-20261023

Conversation

@joshavant

@joshavant joshavant commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What Problem This Solves

The source-pinned action otherwise defaults to mutable latest, allowing historical cached scanner contents. Select the released TruffleHog3.99.4 scanner image whose actual payloads have incident-hardening evidence.

User Impact

CI secret scanning uses the selected qualified runtime. Product code/data and scan policy remain unchanged. This is a scanner-input change, not complete repository or fleet remediation; upstream image version tags remain mutable.

Why This Change Was Made

Use the pinned action's existing version input. Preserve its source reference, image namespace, scan ranges, --only-verified/--debug where already selected, --fail/--no-update, triggers, permissions and failure gate. All caller action references were source-verified to use identical action.yml bytes that run IMAGE:VERSION.

Evidence

  • Touched workflow passes actionlint1.7.12. All-workflow analysis reports the existing unconfigured xcode-27 custom runner in ci.yml; exact base/candidate output is identical. No ignore or rule disable was added. git diff --check passes. Fresh independent P0–P2 review is scoped-clean.
  • Reuse exact canonical image qualification: captured Linux ARM64 image entrypoint and extracted AMD64 image executable match official release payloads and Go1.27.3 build metadata. Across68 component cases:14 original incident endpoints in each applicable default/image-CA/explicit old-CA mode, legitimate public/private HTTPS and hostname/untrusted controls, plus the preserved synthetic verified git-scan failure gate. This is reused exact-artifact evidence, not a new whole-action or product run for this repository. AMD64 execution was under full-system QEMU TCG, not native hardware or actual AMD64 OCI entrypoint proof.
  • Actual GitHub AMD64 composite execution remains PR CI evidence. Every built-in detector, external Git/SSH/OpenSSL path, historical runner caches and deployed fleet remain outside this component proof. No release/deployment was run.
Exact source and artifact identities

Candidate b543c79d3ff820a22212471b57df37959fede7d7, base 4a8f491bebeca8adb6f492c209804855ef49f301, tree 02291981ef3d0f8277f68fc5822c390e30d6b3e5. Workflow SHA256 9d3c56f318ae4b93924d0b03ef2c8b0e70c7c620bb57dc92cf065e056e08c645.

Captured canonical3.99.4 image index SHA256 bf9238f5bdf26ac28230d4b0bae5162a752b151bf10bea612dad7a62da938731; ARM64 image payload b57ff51268b83496fd58889b252e61549cd1071467aed4f4706b1df53ec13150; AMD64 payload 70b9108715250b19518b03acea56b2f4907a36dcfaaf77693444bdc007a761b1. Action body SHA256 c3847cdbebcf469ef336c9b3f32dc6075ed65523e80e661cf404daebd57e5ba9. Qualification retains upstream +dirty/build-metadata limitations rather than claiming a reproducible source attestation.

Inspectable additional validation evidence

Inspectable canonical scanner-image TLS observations

Exact consumer head b543c79d3ff820a22212471b57df37959fede7d7; .github/workflows/secret-scan.yml SHA256 9d3c56f318ae4b93924d0b03ef2c8b0e70c7c620bb57dc92cf065e056e08c645 selects TruffleHog3.99.4 through the unchanged action. These are reused actual qualified component/image observations, not a newly executed whole consumer workflow.

The consumer action bytes and version input match the canonical Gitcrawl qualification. Existing exact-head consumer CI separately exercises the hosted scanner step. The normal upstream version tag remains mutable; this evidence identifies the tested artifact, not every historical runner cache.

Linux ARM64 actual OCI entrypoint

Image/binary identity:

{
  "imageReference": "ghcr.io/trufflesecurity/trufflehog@sha256:adb1cb57ef6196ea097e86c8fdb18f9df327f3865b0444c313d0303efcd9702d",
  "binarySHA256": "b57ff51268b83496fd58889b252e61549cd1071467aed4f4706b1df53ec13150",
  "privateRequests": [
    {
      "case": "private-CA",
      "bodySHA256": "d39a20381bef4f59ed806646d146317f79fdd63468bfd1949c4e0b7a05ff201c",
      "tls": "TLSv1.3"
    },
    {
      "case": "git-verified-gate",
      "bodySHA256": "d39a20381bef4f59ed806646d146317f79fdd63468bfd1949c4e0b7a05ff201c",
      "tls": "TLSv1.3"
    }
  ],
  "syntheticRepo": {
    "base": "8fedc5b6baba0d5f4e447318ba223947ea62a5a7",
    "head": "e45261687ca9acb003eddbff6a6b74098c721688"
  },
  "verdict": "passed-focused-image-entrypoint-and-git-gate",
  "limits": "LinuxARM64 actualimageentrypoint/customverifier only, not everybuiltin/externalclient/nativeAMD64image/fleet. DefaultUnknownIssuer is rejection notkey-specific; explicitoldCA retains exactobservedx509error."
}

Per-case actual verifier output, projected from retained JSON stdout (all record hashes retained locally):

Case Verified Actual VerificationError / outcome
private-CA True HTTP response accepted
private-untrusted False x509: certificate signed by unknown authority
hostname False x509: cannot validate certificate for because it doesn't contain any IP SANs
legitimate-public True HTTP response accepted
incident-00-oldCA False x509: no valid chains built
incident-00-default False x509: certificate signed by unknown authority
incident-01-oldCA False x509: no valid chains built
incident-01-default False x509: certificate signed by unknown authority
incident-02-default False x509: certificate signed by unknown authority
incident-02-oldCA False x509: no valid chains built
incident-03-default False x509: certificate signed by unknown authority
incident-03-oldCA False x509: no valid chains built
incident-04-oldCA False x509: no valid chains built
incident-04-default False x509: certificate signed by unknown authority
incident-05-default False x509: certificate signed by unknown authority
incident-05-oldCA False x509: no valid chains built
incident-06-default False x509: certificate signed by unknown authority
incident-06-oldCA False x509: no valid chains built
incident-07-oldCA False x509: no valid chains built
incident-07-default False x509: certificate signed by unknown authority
incident-08-default False x509: certificate signed by unknown authority
incident-08-oldCA False x509: no valid chains built
incident-09-default False x509: certificate signed by unknown authority
incident-09-oldCA False x509: no valid chains built
incident-10-default False x509: certificate signed by unknown authority
incident-10-oldCA False x509: no valid chains built
incident-11-default False x509: certificate signed by unknown authority
incident-11-oldCA False x509: no valid chains built
incident-12-default False x509: certificate signed by unknown authority
incident-12-oldCA False x509: no valid chains built
incident-13-oldCA False x509: no valid chains built
incident-13-default False x509: certificate signed by unknown authority
git-verified-gate True HTTP response accepted
git-unverified-control exit=0

Actual stderr/stdout examples are bounded below. The synthetic custom detector exercises the selected verifier; it is not a claim that every built-in detector/external transport is covered.

incident-00-oldCA stdout SHA256 adaeeb1fa983bb7ee3dd80f3cbfc3f4fae4030bb23e33ebcb98bd41a9445ff4b:

{
  "Verified": false,
  "VerificationError": "x509: no valid chains built",
  "VerificationFromCache": false
}

Linux AMD64 image ELF under full-system emulation

Image/binary identity:

{
  "imageReference": "ghcr.io/trufflesecurity/trufflehog@sha256:a3a8f49c82805a99bba4cec01c0cce2f3daeaeb59884eef70aafc88715003d1e",
  "binarySHA256": "70b9108715250b19518b03acea56b2f4907a36dcfaaf77693444bdc007a761b1",
  "privateRequests": [
    {
      "case": "private-CA",
      "bodySHA256": "d39a20381bef4f59ed806646d146317f79fdd63468bfd1949c4e0b7a05ff201c",
      "tls": "TLSv1.3"
    },
    {
      "case": "git-verified-gate",
      "bodySHA256": "d39a20381bef4f59ed806646d146317f79fdd63468bfd1949c4e0b7a05ff201c",
      "tls": "TLSv1.3"
    }
  ],
  "syntheticRepo": {
    "base": "79afa832b8811f4aafdf60f23ea6644be8d69a3e",
    "head": "ca06eab2acd67b386b3ce69b91313ce63776a595"
  },
  "verdict": "passed-extracted-amd64-image-native-custom-verifier-and-git-gate",
  "limits": "ExtractedactualLinuxAMD64imageELF runs infullsystemx86_64QEMUTCGguest; imageCAbundleexplicitfile/emptydir ratherthanOCIentrypoint. Notnativehardware/timing,notactualAMD64containerorallbuiltins/externalclient/fleet. DefaultUnknownIssuer is rejection notkey-specific; explicitoldCA retains exactobservedx509error."
}

Per-case actual verifier output, projected from retained JSON stdout (all record hashes retained locally):

Case Verified Actual VerificationError / outcome
private-CA True HTTP response accepted
private-untrusted False x509: certificate signed by unknown authority
hostname False x509: cannot validate certificate for because it doesn't contain any IP SANs
legitimate-public True HTTP response accepted
incident-00-oldCA False x509: no valid chains built
incident-00-default False x509: certificate signed by unknown authority
incident-01-default False x509: certificate signed by unknown authority
incident-01-oldCA False x509: no valid chains built
incident-02-default False x509: certificate signed by unknown authority
incident-02-oldCA False x509: no valid chains built
incident-03-default False x509: certificate signed by unknown authority
incident-03-oldCA False x509: no valid chains built
incident-04-default False x509: certificate signed by unknown authority
incident-04-oldCA False x509: no valid chains built
incident-05-default False x509: certificate signed by unknown authority
incident-05-oldCA False x509: no valid chains built
incident-06-default False x509: certificate signed by unknown authority
incident-06-oldCA False x509: no valid chains built
incident-07-default False x509: certificate signed by unknown authority
incident-07-oldCA False x509: no valid chains built
incident-08-default False x509: certificate signed by unknown authority
incident-08-oldCA False x509: no valid chains built
incident-09-oldCA False x509: no valid chains built
incident-09-default False x509: certificate signed by unknown authority
incident-10-default False x509: certificate signed by unknown authority
incident-10-oldCA False x509: no valid chains built
incident-11-oldCA False x509: no valid chains built
incident-11-default False x509: certificate signed by unknown authority
incident-12-default False x509: certificate signed by unknown authority
incident-12-oldCA False x509: no valid chains built
incident-13-default False x509: certificate signed by unknown authority
incident-13-oldCA False x509: no valid chains built
git-verified-gate True HTTP response accepted
git-unverified-control exit=0

Actual stderr/stdout examples are bounded below. The synthetic custom detector exercises the selected verifier; it is not a claim that every built-in detector/external transport is covered.

incident-00-oldCA stdout SHA256 92923f530253b8b73a3f2eaf55a315211e756b519914247b687a1971c8aaa0a9:

{
  "Verified": false,
  "VerificationError": "x509: no valid chains built",
  "VerificationFromCache": false
}

Historical-root bundle SHA256 c3aa6ce83618c247fdeb0afad3a4eb1d01da2eb9035defe70f74c4bbaaca986f. Existing matched historical-store controls established the fixture chains were valid/accepted before remediation. Default UnknownIssuer alone is not key-specific proof; explicit old-root-store failures carry the stronger evidence. No timeout, DNS error or setup failure is counted as rejection.

ARM archive SHA256 ce12d49b56d5cb1ec2a3d9c9ae2add6e7d39e5d7104f3e2bca75fa2614118381; AMD archive 6310c1d1299ea1b05af4fe2558e4b4dbcf67018e0fb03c28170f18caab0bbe39. No native AMD64 OCI entrypoint, native macOS/Windows, all-detector or fleet-delivery claim.

Only synthetic loopback/private fixtures were used; loopback addresses are redacted in the projected traces.

@joshavant
joshavant requested a review from a team as a code owner October 23, 2026 22:08
@clawsweeper

clawsweeper Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@github-actions github-actions Bot added the fix label Oct 23, 2026
@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. labels Oct 23, 2026
@clawsweeper

clawsweeper Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex review: needs maintainer review before merge.

What this changes

This PR selects TruffleHog image version 3.99.4 through the pinned action’s existing version input.

Example: A secret-scanning runner has an older cached latest image.

  • Before: The action requests ghcr.io/trufflesecurity/trufflehog:latest and can reuse that cached image.
  • After: The action requests ghcr.io/trufflesecurity/trufflehog:3.99.4.

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) A minimal, useful repair with inspectable production-path observations and no actionable findings.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The selected 3.99.4 image is exercised through its real ARM64 OCI entrypoint and extracted AMD64 executable under full-system emulation; inspectable output demonstrates incident-certificate rejection, trusted HTTPS acceptance, and the synthetic verified-secret failure gate. Shared qualification also records hosted AMD64 composite execution of the captured image index, while exact-head target jobs confirm successful scanner-step execution. This addresses the prior rank-up request without claiming every detector, external transport, historical cache, or deployed fleet was qualified.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: Updating the action source does not select its scanner runtime, so secret scans can reuse an older cached latest image.
Reason: The supplied maintainer direction selects a qualified runtime through an existing upstream input with one focused workflow change.

Merge readiness

✅ Ready for maintainer review

This PR makes a focused scanner-runtime repair that main lacks; no actionable patch defects remain.

Priority: P2
Reviewed head: b543c79d3ff820a22212471b57df37959fede7d7

Before merge

None.

Findings

None.

Agent review details

How this fits together

GitHub push and pull-request events provide a commit range to a workflow that runs TruffleHog and fails when verified credentials are detected.

flowchart TD
  A[Push or pull request] --> B[Resolve commit range]
  B --> C[Pinned TruffleHog action]
  C --> D[Scanner image 3.99.4]
  D --> E[Verify detected credentials]
  E --> F[Workflow result]
Loading

Technical review

Best possible solution:

Use the existing version input to select the qualified scanner runtime while preserving the established secret-scanning gate.

Do we have a high-confidence way to reproduce the issue?

The pinned action defaults to latest and invokes docker run without forcing a pull, establishing the cached-image reuse path from source.

Is this the best way to solve the issue?

The single existing input is the smallest complete fix for explicit runtime selection, with upstream tag mutability accurately acknowledged.

AGENTS.md: not found in the target repository.

Codex review notes: model internal, reasoning medium; reviewed against 4a8f491bebec.

Provenance checked

  • TruffleHog runtime selection changes intended behavior with a stated reason (b5e289c: chore(ci): add crawl security baseline #30 established a standalone verified-secret gate; this PR explains why its inherited implicit runtime default should become an explicit version.)

Testing

Proof path: shipped entry point.

Security

None.

Evidence

What I checked:

  • Exact introduced change: The introduction adds only version: "3.99.4"; main and v0.6.9 omit it. Action source, permissions, scan ranges, flags, and failure handling are unchanged. (.github/workflows/secret-scan.yml:57, b543c79d3ff8)
  • Executed dependency contract: The workflow directly executes this action, whose version input defaults to latest and becomes IMAGE:VERSION in docker run; the invocation retains --fail and --no-update. (action.yml:22, e63326d6545d)
  • Added inspectable qualification observations: The complete body was read and matches source SHA256 704e4fc7db3fe8e92ab25692051f09969b8acc2e6703b7963b1fd1f5bda32d50. It now includes actual verifier output for incident certificates, legitimate HTTPS, and hostname/untrusted controls on ARM64 OCI and extracted AMD64 ELF, addressing the previous review’s optional rank-up request. (b543c79d3ff8)
  • Shared exact-artifact qualification: This PR explicitly relies on fix(ci): pin qualified TruffleHog runtime image gitcrawl#272. Its workflow uses the identical action SHA and version input; retained output shows incident rejection, trusted HTTPS acceptance, synthetic verified-secret exit 183, unverified-control exit 0, and hosted image index bf9238f5bdf26ac28230d4b0bae5162a752b151bf10bea612dad7a62da938731. (.github/workflows/secret-scan.yml:52, 477b32f8f036)
  • Exact-head scanner execution: The TruffleHog OSS step succeeded at the reviewed head in https://github.com/openclaw/notcrawl/actions/runs/40031617794/job/120680973531; both scanner checks passed. Detailed log retrieval was blocked by the storage-host allowlist, which does not invalidate the supplied component output. (.github/workflows/secret-scan.yml:50, b543c79d3ff8)
  • Original purpose and feature ownership: The readable creation diff and chore(ci): add crawl security baseline #30 establish the verified-secret gate; subsequent history shows repeated tooling updates by Peter Steinberger. Rename-following history stops at an unavailable creation-era promisor object, but the creation diff and current-main blame remain readable. (.github/workflows/secret-scan.yml:50, b5e289c4bd77)

Likely related people:

  • Vincent Koc: Raw commit b5e289c adds .github/workflows/secret-scan.yml:50 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: b5e289c4bd77; files: .github/workflows/secret-scan.yml)
  • Peter Steinberger: Raw commit a0dff68 adds .github/workflows/secret-scan.yml:52 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: a0dff68d823b; files: .github/workflows/secret-scan.yml)

Labels

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P2: Explicit runtime selection improves the security gate without evidence of an urgent workflow outage.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.
  • proof: sufficient: Contributor real behavior proof is sufficient.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

History

Review history (1 earlier review cycle)
  • reviewed 2026-10-23T22:20:43.002Z sha b543c79 :: needs maintainer review before merge. :: none

Reviewed October 23, 2026, 10:23 PM ET / October 24, 2026, 02:23 UTC (Revision 2).

@joshavant

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

The PR body now includes inspectable exact-artifact observations for the requested evidence gap, with platform and component-reuse limits stated. Product source is unchanged.

@clawsweeper

clawsweeper Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Oct 24, 2026
@joshavant
joshavant merged commit 73bef33 into main Oct 25, 2026
27 checks passed
@joshavant
joshavant deleted the security/emudhra-trufflehog-runtime-20261023 branch October 25, 2026 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants