Skip to content

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

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 existing SC2129 style advice in publish-discord-backup.yml; exact base/candidate output is identical. No ignore or rule disable was added. git diff --check passes. Fresh independent P0–P3 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 b1adfe7f97b2176f42f9862d0f0f0f865519aa6f, base c56030d8b6bf6314d1814cf840b3247df21a8800, tree f2f7dde251d06f5aa068a12c3491d6dd27038226. Workflow SHA256 04d4d25b521b994249132efad3792e34c07331e13656fd5fd150d93b511820ec.

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 b1adfe7f97b2176f42f9862d0f0f0f865519aa6f; .github/workflows/secret-scan.yml SHA256 04d4d25b521b994249132efad3792e34c07331e13656fd5fd150d93b511820ec 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:07
@clawsweeper

clawsweeper Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
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.

@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
Contributor

Codex review: needs maintainer review before merge.

What this changes

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

Example: The verified-secret workflow runs for a pull request.

  • Before: The source-pinned action runs ghcr.io/trufflesecurity/trufflehog:latest.
  • After: The same action runs ghcr.io/trufflesecurity/trufflehog:3.99.4 with the existing scan range and failure flags.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A minimal, correct change with sufficient scoped runtime evidence; the qualification transparently combines reused component observations with hosted consumer execution.
Proof confidence 🐚 platinum hermit (4/6) Sufficient (live_output): The expanded body ties the selected 3.99.4 artifacts to actual ARM64 scanner-image entrypoint output and emulated AMD64 image-binary output: legitimate public/private TLS succeeds, hostname and untrusted controls fail, historical incident chains are rejected, and a verified synthetic credential retains the failing git-scan gate. The action-byte hash independently matches, and the exact-head hosted scanner step succeeded. This is scoped component reuse rather than native AMD64 incident-fixture or fleet-remediation proof.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Product

Kind: Maintenance · Worth it: Yes · Fix scope: Complete
User problem: Repository maintainers cannot infer the scanner runtime from the pinned action source because its default image tag is latest.
Reason: The supplied maintainer-authored context establishes direction, and the single existing-input selection delivers qualified runtime control without expanding product configuration or scan policy.

Merge readiness

✅ Ready for maintainer review

Keep this PR open for landing: it makes a useful, minimal scanner-selection change that current main lacks, and this review found no concrete merge blocker.

Priority: P2
Reviewed head: b1adfe7f97b2176f42f9862d0f0f0f865519aa6f

Before merge

None.

Findings

None.

Agent review details

How this fits together

GitHub Actions passes the checked-out repository and commit range to TruffleHog, which verifies detected credentials and returns the secret-scanning gate result.

flowchart LR
  A[Push or pull request] --> B[Checkout repository]
  B --> C[Resolve commit range]
  C --> D[Pinned TruffleHog action]
  D --> E[Scanner image 3.99.4]
  E --> F[Verified secret gate]
Loading

Technical review

Best possible solution:

Land the existing one-line scanner selection with the scan policy and action source preserved.

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

Current main omits version, and the exact upstream action defaults it to latest; this establishes the runtime-selection problem without asserting that a particular runner currently holds an affected cached image.

Is this the best way to solve the issue?

The existing action input is the smallest complete way to select the qualified release while preserving the established gate; the body accurately acknowledges that version tags remain mutable.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 111e9326440d.

Provenance checked

Testing

Proof path: shipped entry point.

Security

None.

Evidence

What I checked:

  • Minimal change absent from main: The pinned introduction diff adds only version: "3.99.4" at line 67; fetched main and release v0.17.0 still omit that input. Scan ranges, permissions, action source, verification flags and failure handling remain intact. (.github/workflows/secret-scan.yml:67, b1adfe7f97b2)
  • Expanded evidence and exact-head execution: The complete PR body supplies actual ARM64 image-entrypoint and emulated AMD64 image-binary observations, including legitimate TLS acceptance, incident-chain rejection and the synthetic verified-secret failure gate. The exact-head hosted TruffleHog step also succeeded: https://github.com/openclaw/discrawl/actions/runs/40031589622/job/120680886445. Raw hosted logs redirect to a blocked storage host, so their contents were not inspected; the supplied observations remain independently inspectable. (.github/workflows/secret-scan.yml:67, b1adfe7f97b2)
  • Executed dependency contract verified: This workflow executes the upstream composite action, establishing the dependency-policy boundary. Its action.yml defaults version to latest and passes IMAGE:VERSION directly to docker run while retaining --fail and --no-update. Its SHA256 matches the qualification evidence: c3847cdbebcf469ef336c9b3f32dc6075ed65523e80e661cf404daebd57e5ba9. No root AGENTS.md exists at this revision. (action.yml, e76dff8a7e57)
  • Credited shared component qualification: The PR explicitly relies on fix(ci): pin qualified TruffleHog runtime image gitcrawl#272 for qualification of the same scanner artifacts and action bytes. Its inspectable observations show incident-chain rejection, legitimate private-CA acceptance and git-scan exit 183 for a verified synthetic credential. The root AGENTS.md was read; its workspace rules require no action in this read-only review. (477b32f8f036)
  • Original purpose and feature ownership: chore(ci): add crawl security baseline #57 established the standalone verified-secret gate; subsequent history includes Vincent Koc’s scan-range repair and Peter Steinberger’s repeated scanner and workflow updates. CODEOWNERS routes workflows to openclaw/openclaw-secops. History tracing reaches the documented file-creation boundary, where an unavailable predecessor blob stops --follow. (.github/workflows/secret-scan.yml:65, 111e9326440d)

Likely related people:

  • Vincent Koc: Raw commit cd3450e adds .github/workflows/secret-scan.yml:49 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: cd3450e06acd; files: .github/workflows/secret-scan.yml)
  • Peter Steinberger: Raw commit 860bfc1 adds .github/workflows/secret-scan.yml:19 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 860bfc181b46; files: .github/workflows/secret-scan.yml)

Labels

Label changes:

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

Label justifications:

  • P2: This is focused security-scanner maintenance with limited repository-CI scope and no demonstrated urgent product outage.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit 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:40.513Z sha b1adfe7 :: 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
Contributor

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary 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 df69b29 into main Oct 25, 2026
30 checks passed
@joshavant
joshavant deleted the security/emudhra-trufflehog-runtime-20261023 branch October 25, 2026 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary 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.

1 participant