Skip to content

fix(ci): unblock the audit gate and raise the callback secret floor - #53

Merged
edycutjong merged 1 commit into
mainfrom
fix/audit-gate-and-callback-secret-floor
Aug 13, 2026
Merged

fix(ci): unblock the audit gate and raise the callback secret floor#53
edycutjong merged 1 commit into
mainfrom
fix/audit-gate-and-callback-secret-floor

Conversation

@edycutjong

Copy link
Copy Markdown
Owner

Why CI is red

The Security — dependencies · secrets job has failed on every run since 2026-08-12T19:22Z, when GHSA-jmr9-qjv8-65gv was updated. The 14:35Z run that day was green; the 23:10Z run — a release-please version bump with no source change — was red. No code change caused it.

None can clear it either:

  • extract-zip@2.0.1 is both the latest published release and the vulnerable one
  • the advisory's firstPatchedVersion is null and the package is unmaintained
  • so neither a version bump nor a pnpm.overrides entry resolves it

It reaches us only as dev tooling — @lhci/cli > lighthouse > puppeteer-core > @puppeteer/browsers > extract-zip — where it unpacks a browser download from a trusted source during pnpm lighthouse. It is not in the shipped agent's dependency graph.

This was skipping the whole pipeline

quality declares needs: [security], and contracts, e2e and perf all gate on quality. One unfixable transitive advisory was therefore skipping Quality, Contracts, E2E, Perf and Ready-to-ship — and the gitleaks scan and check-no-credentials.sh too, since both sit after the failing step inside the same job. The security gate was the part that wasn't running.

The fix

Exempted by advisory id via pnpm's auditConfig, rather than dropping the gate to --prod — every other high in every other dev dependency still fails CI. pnpm audit --audit-level=high now exits 0 and still prints the advisory as 1 ignored rather than hiding it. Carries a comment recording why and when to re-check.

Weak-credential gap, found while confirming the rest of the pipeline

REVOKER_CALLBACK_SECRET had no length floor, so a three-character token was accepted as a valid bearer credential on POST /revoke — the one endpoint that submits transactions. The 20/min limiter bounds online guessing but does not end it: a four-character lowercase secret still falls inside a day.

Anything under 16 characters is now normalised to unset, leaving the endpoint closed and reporting revokeCallback: "unconfigured" rather than looking armed. The 503 names which of the two faults it is.

Enforced on both sides. scripts/deploy-workflow.ts already had its own 8-character check, which would have become a trap once the server floor landed: the deploy would report success and wire the token into the live workflow, and the agent would then refuse every callback with a 503 nobody is watching for. Raised to 16 to match, with the two sites cross-referenced in comments.

Its base64 fixture was also corrected from 12 characters to the 44 that openssl rand -base64 32 actually produces — the command named in the error message has to produce something the check accepts, and a token-sized fixture would have let the floor regress without failing the test.

Verification

Gate Result
pnpm audit --audit-level=high exit 0 (1 ignored)
pnpm test 726 passed (+2 new)
pnpm lint clean
pnpm typecheck clean
pnpm install --frozen-lockfile unaffected

Scope note

Everything else in the audit came back clean: CodeQL 0 open alerts, no secrets in history (every 0x[a-f0-9]{64} in tracked files is a Sepolia tx hash), and the /revoke auth path is otherwise well-hardened — constant-time compare, rate limiting applied before the secret is examined, a body cap measured on received bytes rather than trusted Content-Length, owner taken from config and never from the request, and tx-hash idempotency keys.

The Security job has failed on every run since 2026-08-12 19:22Z, when
GHSA-jmr9-qjv8-65gv (extract-zip unvalidated symlink path traversal) was
updated. No code change caused it and none can clear it: extract-zip 2.0.1
is both the latest published release and the vulnerable one, the package is
unmaintained, and the advisory has no patched version — so neither a bump
nor a `pnpm.overrides` entry resolves it.

It reaches us only as dev tooling, via @lhci/cli > lighthouse >
puppeteer-core > @puppeteer/browsers > extract-zip, where it unpacks a
browser download from a trusted source during `pnpm lighthouse`. It is not
in the shipped agent's dependency graph.

Exempted by advisory id through pnpm's auditConfig rather than dropping the
gate to --prod, so every other high in every other dev dependency still
fails CI. `pnpm audit --audit-level=high` now exits 0 and still reports the
advisory as ignored rather than hiding it.

This mattered more than one red check: `quality` declares `needs: [security]`
and contracts, e2e and perf all gate on `quality`, so a single unfixable
transitive advisory was skipping the entire pipeline — including the gitleaks
scan and check-no-credentials.sh, which sit after the failing step in the
same job. The security gate was the thing not running.

Also closes a weak-credential gap found while confirming the rest of the
pipeline is sound: REVOKER_CALLBACK_SECRET had no length floor, so a
three-character token was accepted as a valid bearer credential on POST
/revoke, the one endpoint that submits transactions. The 20/min limiter
bounds online guessing but does not end it — a four-character lowercase
secret still falls inside a day. Anything under 16 characters is now
normalised to unset, which leaves the endpoint closed and reports
revokeCallback "unconfigured" rather than looking armed.

The floor is enforced on both sides. scripts/deploy-workflow.ts already had
its own 8-character check, which would have become a trap: the deploy would
report success and wire the token into the live workflow, and the agent
would then refuse every callback with a 503 nobody is watching for. Raised
to 16 to match, and its base64 fixture corrected from 12 characters to the
44 that `openssl rand -base64 32` actually produces — a token-sized fixture
would have let the floor regress without failing the test.

Verified locally: 726 tests pass, lint and typecheck clean, audit exits 0,
and `pnpm install --frozen-lockfile` is unaffected.
@edycutjong
edycutjong merged commit d11aa52 into main Aug 13, 2026
9 checks passed
@edycutjong
edycutjong deleted the fix/audit-gate-and-callback-secret-floor branch August 13, 2026 00:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant