From 134963647b39c64bc6966a99115825b5f63baa95 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:54:40 -0400 Subject: [PATCH] chore(security): suppress pre-existing history scanner false-positives (#56) Adds repo-local suppressions for 5 verified-FP gitleaks findings that block pushes (forcing --no-verify), all in committed history / docs / CI fixtures: - .env.ci (dev-only e2e values, intentionally committed) - .env.example (placeholders) - .github/ci/fake_github_app_key.pem (throwaway CI test key) - INSTALLATION.md (example GITHUB_APP_PRIVATE_KEY .env block) - README.md (prose mis-matched by the generic-api-key heuristic) Repo-local (not machine-level) so they load in git worktrees too. Also drops the now-obsolete OSWE-IAC-AUDIT-01 suppression (B-1, fixed in #55). --- .security-review/suppressions.json | 83 +++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/.security-review/suppressions.json b/.security-review/suppressions.json index 47ed2662..50fed478 100644 --- a/.security-review/suppressions.json +++ b/.security-review/suppressions.json @@ -1,22 +1,12 @@ { "suppressions": [ - { - "id": "OSWE-IAC-AUDIT-01", - "title": "Dev-branch infra OIDC role can assume the account-wide CDK cfn-exec admin role (cdk-hnb659fds-*), a path to mutating prod", - "file": "infra/lib/constructs/github-deploy-roles.ts", - "severity": "high", - "status": "confirmed", - "suppression_justification": "PRE-EXISTING and NOT introduced or worsened by the T7+T19 change (the assets bucket / app-role PutObject / SSM deploy doc). This is the known single-account-wide CDK cfn-exec residual already documented in infra/lib/config.ts:31-34 and the github-deploy-roles.ts construct comment, accepted at the T4 GPT-4.1 IAM cross-review and the v5 plan-review. WHO can assume each env's infra role is exact-subject scoped (StringEquals on the dev ref / prod environment); the residual is the shared account-wide cfn-exec-role that every env's infra role can reach. The tracked fix is per-env CDK bootstrap qualifiers so each env's infra role assumes its own env-scoped cfn-exec-role. Suppressed for THIS change's gate because it is out-of-diff and unchanged; surfaced to Adam for scheduling the per-env-bootstrap remediation.", - "owner": "adam@seahavenind.com", - "added": "2026-06-26" - }, { "id": "OSWE-IAC-SECRETS-LIST-01", - "title": "EC2 instance role grants BatchGetSecretValue + ListSecrets on \"*\" (operation-level; secret-NAME enumeration account-wide)", + "title": "EC2 instance role grants BatchGetSecretValue on \"*\" (operation-level; secret-NAME existence enumeration account-wide)", "file": "infra/lib/constructs/instance-role.ts", "severity": "low", "status": "confirmed", - "suppression_justification": "ACCEPTED LOW residual, metadata-only. fetch-config.sh materializes the .env via `batch-get-secret-value --filters Key=name,Values=open-swe-/`. With a name FILTER, both BatchGetSecretValue (a collection call) and ListSecrets are authorized by AWS against `*`, NOT a per-secret ARN — a prefix-scoped ARN AccessDenies the call (confirmed empirically on i-0af4e03e8bf70e6c3). So the two `*` grants are operation-level, not value-level. Secret VALUES remain strictly gated by the PREFIX-scoped GetSecretValue/DescribeSecret on secret:open-swe-/* (GetSecretValue is checked per-secret even within the batch), so cross-env VALUE isolation is preserved; only NAMES/tags/descriptions are enumerable, within Sea Haven's own single-tenant account 328440206208. Confirmed by GPT-4.1 IAM cross-review (BLOCK: none) and the iac-iam detector (one low residual, no critical/high). Future hardening to eliminate BOTH `*` grants: switch fetch-config.sh to an explicit `--secret-id-list` (no filter), which lets BatchGetSecretValue be prefix-scoped and needs no ListSecrets.", + "suppression_justification": "ACCEPTED LOW residual, metadata-only. secretsmanager:BatchGetSecretValue is a collection action that AWS cannot scope to a per-secret ARN, so it is granted on `*` (documented in commit 3c69dd9d and the construct comment). Secret VALUES remain strictly gated by the PREFIX-scoped GetSecretValue/DescribeSecret on secret:open-swe-/* (checked per-secret even within the batch), so cross-env VALUE isolation is preserved; only a name EXISTENCE oracle remains, within Sea Haven's single-tenant account 328440206208. ListSecrets is intentionally NOT granted (so name FILTER enumeration AccessDenies). Confirmed by GPT-4.1 IAM cross-review (no BLOCK) and the iac-iam detector (one low residual, no critical/high).", "owner": "adam@seahavenind.com", "added": "2026-06-26" }, @@ -54,8 +44,73 @@ "rule": "CWE-798", "severity": "high", "status": "false-positive", - "justification": "Test fixture, not a real credential. The literal \"ghp_secret\" is a fake GitHub token used by the cached-token TTL/revocation unit tests to exercise cache_github_token_for_thread / get_github_token expiry and invalidation. It is not a valid 40-char GitHub PAT, is never a live secret, and is scoped to the unit test only. Pre-existing test fixture, not introduced by this change.", - "suppression_justification": "Test fixture, not a real credential. The literal \"ghp_secret\" is a fake GitHub token used by the cached-token TTL/revocation unit tests to exercise cache_github_token_for_thread / get_github_token expiry and invalidation. It is not a valid 40-char GitHub PAT, is never a live secret, and is scoped to the unit test only. Pre-existing test fixture, not introduced by this change.", + "justification": "Test fixture, not a real credential. The literal \"ghp_secret\" is a fake GitHub token used by the cached-token TTL/revocation unit tests. Not a valid 40-char GitHub PAT, never a live secret, scoped to the unit test only.", + "suppression_justification": "Test fixture, not a real credential. The literal \"ghp_secret\" is a fake GitHub token used by the cached-token TTL/revocation unit tests. Not a valid 40-char GitHub PAT, never a live secret, scoped to the unit test only.", + "owner": "adam@seahavenind.com", + "added": "2026-06-29" + }, + { + "id": "gitleaks-generic-api-key-24", + "title": "Dev-only CI env value flagged in .env.ci (history-only; file not at HEAD)", + "file": ".env.ci", + "line": 24, + "rule": "gitleaks-generic-api-key", + "severity": "high", + "status": "false-positive", + "justification": "False positive. .env.ci is the e2e CI env file (added in commit 5a52b9b2 'ci: run playwright e2e tests') holding DELIBERATELY-FAKE, dev-only values explicitly marked 'committed intentionally' (e.g. GITHUB_WEBHOOK_SECRET=dev-secret and a dev-only Fernet TOKEN_ENCRYPTION_KEY used solely by the Playwright e2e suite). No production secret: real prod values live in Secrets Manager (open-swe-prod/*). gitleaks scans committed history so it flags this even though the file is not present at HEAD.", + "suppression_justification": "Dev-only CI fixture value, intentionally committed for the e2e suite; not a production secret (prod secrets are in Secrets Manager). Flagged from git history; file not present at HEAD.", + "owner": "adam@seahavenind.com", + "added": "2026-06-29" + }, + { + "id": "gitleaks-generic-api-key-3", + "title": "Placeholder flagged in .env.example (history-only; file not at HEAD)", + "file": ".env.example", + "line": 3, + "rule": "gitleaks-generic-api-key", + "severity": "high", + "status": "false-positive", + "justification": "False positive. .env.example contains placeholder/example values only, by definition not real secrets. gitleaks scans committed history so it flags the placeholder even though the file is not present at HEAD.", + "suppression_justification": "Example/placeholder value in a committed .env.example; flagged from git history. Not a real secret.", + "owner": "adam@seahavenind.com", + "added": "2026-06-29" + }, + { + "id": "gitleaks-private-key-1", + "title": "Fake CI RSA key flagged in .github/ci/fake_github_app_key.pem (history-only)", + "file": ".github/ci/fake_github_app_key.pem", + "line": 1, + "rule": "gitleaks-private-key", + "severity": "high", + "status": "false-positive", + "justification": "False positive. This is a throwaway test RSA key (the filename is literally 'fake_github_app_key.pem') referenced by .env.ci for the Playwright e2e suite. It is not a production GitHub App key (the real prod key is in Secrets Manager open-swe-prod/GITHUB_APP_PRIVATE_KEY). gitleaks scans committed history; the file is not present at HEAD.", + "suppression_justification": "Deliberately-fake CI test key for the e2e suite; not a production GitHub App key. Flagged from git history; file not present at HEAD.", + "owner": "adam@seahavenind.com", + "added": "2026-06-29" + }, + { + "id": "gitleaks-private-key-185", + "title": "Documentation example PEM flagged in INSTALLATION.md (CWE-798)", + "file": "INSTALLATION.md", + "line": 185, + "rule": "gitleaks-private-key", + "severity": "high", + "status": "false-positive", + "justification": "False positive. INSTALLATION.md shows the .env format with an example GITHUB_APP_PRIVATE_KEY=\"-----BEGIN RSA PRIVATE KEY-----...\" block in the setup instructions. It is illustrative documentation, not a real key.", + "suppression_justification": "Documentation example of the GITHUB_APP_PRIVATE_KEY .env format in INSTALLATION.md; not a real key.", + "owner": "adam@seahavenind.com", + "added": "2026-06-29" + }, + { + "id": "gitleaks-generic-api-key-29", + "title": "README prose flagged as a generic API key (CWE-798)", + "file": "README.md", + "line": 29, + "rule": "gitleaks-generic-api-key", + "severity": "high", + "status": "false-positive", + "justification": "False positive. README.md line 29 is descriptive project prose (the 'Open SWE is the open-source version...' paragraph / blog link); gitleaks' generic-api-key entropy heuristic mis-matched a token in the text. No secret is present.", + "suppression_justification": "README descriptive prose mis-matched by the generic-api-key entropy heuristic; no secret present.", "owner": "adam@seahavenind.com", "added": "2026-06-29" }