Skip to content

fix(security): reject malformed dependency-review identity before compare - #1045

Open
cursor[bot] wants to merge 5 commits into
mainfrom
cursor/bc-527d280c-f70e-4274-bf3f-c41170e804cf-54b1
Open

fix(security): reject malformed dependency-review identity before compare#1045
cursor[bot] wants to merge 5 commits into
mainfrom
cursor/bc-527d280c-f70e-4274-bf3f-c41170e804cf-54b1

Conversation

@cursor

@cursor cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Purpose

Close the remaining identity-validation hole on the #810 fail-closed dependency-review gate. #1041 and #1042 already fail closed on HTTP 403/404, empty/malformed status, transport failure, and curl exit 18 with a printed 200. They still interpolate unvalidated BASE_SHA, HEAD_SHA, and REPOSITORY into the compare URL. An empty revision or ../ repository name can therefore reach curl; a forged HTTP 200 writes supported=true.

This is the single integration vehicle for that repair. It continues #1041 (same fail-closed probe, visibility diagnostics, EgressWeave #66 canary, and unskippable pinned action) and supersedes #897, #1033, and #1042 for integration. Do not open further overlapping workflow PRs.

Canary (do not treat as fixed until a post-merge consumer run)

ContextualWisdomLab/EgressWeave#66, Security Scan run 31108241013, job 92638903658 compared 10d0c51d...c038a950, received HTTP 403, skipped the pinned action, and still concluded success. Downstream: ContextualWisdomLab/EgressWeave#76.

Keep #810 open until a protected-main public consumer run proves a non-200 or failed-transfer comparison cannot green this job.

What changed

  • Reject a base or head revision that is not exactly 40 or 64 hexadecimal characters, and a repository name that is not canonical owner/name, before opening a socket (curl exit uncalled).
  • Executable regressions record the exact compare argv so a hardcoded supported=true path cannot satisfy the success contract.
  • The pinned action remains independently unskippable after a successful probe. OSV and Trivy remain separate hard gates.

Tests

Local pytest tests/test_required_workflow_queue_contract.py tests/test_pr_review_autofix_nvidia_nim_contract.py tests/test_pr_governance_audit_contract.py tests/test_codeql_pr_workflow_contract.py tests/test_central_required_workflow_ruleset_audit.py tests/test_opencode_workflow_shell_syntax.py: 117 passed.

Acceptance

Do not close #810 from this change alone. Merge only after exact-current-head deterministic, security, dependency, and required workflows are terminal and clean, current automated review has no valid unresolved finding, and a qualifying counted non-author formal approval exists.

Open in Web View Automation 

seonghobae and others added 5 commits August 17, 2026 00:19
Replay unique #897 source onto current origin/main. Skip shared
ARCHITECTURE/CLAUDE trees. Treat non-200 or failed transport as
unavailable evidence rather than a clean skip.
Close the remaining #810 diagnostic gap:
allowlist public/private/internal/unknown visibility in probe
diagnostics, execute 403/404/empty/malformed regressions, and stop
making the pinned action independently skippable after a successful
probe.

Co-authored-by: Seongho Bae <[email protected]>
Add executable regressions for the EgressWeave #66 canary (HTTP 403
skip-was-success), a bare transport failure, and curl exit 18 with a
printed 200. Record exact SHAs and allowlisted visibility without
leaking the probe token.

Co-authored-by: Seongho Bae <[email protected]>
…arness

Invoke the extracted support probe with an absolute bash path and keep
the fake curl first on PATH so isolated executable regressions can run
without calling the real binary.

Co-authored-by: Seongho Bae <[email protected]>
…pare

Empty or non-hex base/head revisions and non-canonical repository names
no longer reach curl. A forged HTTP 200 therefore cannot write
supported=true. Executable regressions now record the exact compare argv
and keep the pinned action ungated after a successful probe.

Co-authored-by: Seongho Bae <[email protected]>
@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This head closes empty-SHA and owner/../path cases, but it is not yet the integration vehicle.

Remaining buyer-visible gaps on 6a7103a4:

  1. repository_pattern still accepts ContextualWisdomLab/... That interpolates to /repos/ContextualWisdomLab/../dependency-graph/compare/... and can leave the intended repository (CWE-22). The special .github name must stay legal; only complete . / .. segments must fail closed.
  2. Identity-rejection diagnostics echo the raw ${BASE_SHA}, ${HEAD_SHA}, and ${REPOSITORY}. A named ref such as main therefore appears in the log, and an untrusted repository string can break out of the Actions error line.
  3. Curl %{http_code} 000 with transport exit 0 is classified as HTTP 000 instead of unavailable, so operators cannot distinguish a no-status sentinel from a real status.

Do not merge this head. Do not merge #1044 or #1048 for the same reason: #1048 already hides raw named refs and classifies 000, but it still accepts owner/...

Operator next step: review the successor that rejects ./.. segments, omits raw invalid identity, and locks 000 as unavailable. Keep #810 open until a protected-main public consumer run on ContextualWisdomLab/EgressWeave#76 proves a non-200 cannot go green. Automated review is not qualifying approval.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

*) visibility="unknown" ;;
esac
revision_pattern='^[0-9a-fA-F]{40}$|^[0-9a-fA-F]{64}$'
repository_pattern='^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ matches ContextualWisdomLab/.. and ../.github. After interpolation the compare URL becomes /repos/ContextualWisdomLab/../dependency-graph/compare/....

Reject a complete owner or name segment that is . or .. before curl. Keep ContextualWisdomLab/.github legal. Prove this with an executable case that would otherwise print HTTP 200 and write supported=true.

revision_pattern='^[0-9a-fA-F]{40}$|^[0-9a-fA-F]{64}$'
repository_pattern='^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$'
if ! [[ "${BASE_SHA}" =~ $revision_pattern ]] || ! [[ "${HEAD_SHA}" =~ $revision_pattern ]]; then
echo "::error::Dependency review evidence unavailable for ${REPOSITORY} (visibility ${visibility}) at exact base ${BASE_SHA} and head ${HEAD_SHA}: HTTP unavailable; curl exit uncalled. Malformed revision. Supply the pull request's exact 40- or 64-character hex base and head SHAs, then rerun. Failing closed."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error interpolates the untrusted revision and repository. HEAD_SHA=main therefore appears in the log, and a crafted repository string can break the Actions annotation.

Name the failure class and the operator next step only: resupply the pull-request event's exact 40- or 64-character hex SHAs. Do not echo the raw invalid values. After identity is validated, echoing those now-safe SHAs on a later transport failure remains useful.

exit 0
fi
case "$status" in
[0-9][0-9][0-9]) http_status="$status" ;;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

000 matches [0-9][0-9][0-9], so a no-status sentinel with curl exit 0 is recorded as HTTP 000 instead of unavailable.

Classify 000 and empty status as unavailable before the numeric arm, then fail closed. Operators should check runner egress and GitHub service health, then rerun — not treat 000 as a real HTTP status.

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.

security: make central dependency-review unavailability fail closed

2 participants