Skip to content

fix: remediate ReDoS vulnerabilities (Snyk SAST)#4

Open
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1774426451-fix-redos
Open

fix: remediate ReDoS vulnerabilities (Snyk SAST)#4
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1774426451-fix-redos

Conversation

@devin-ai-integration

Copy link
Copy Markdown

Summary

Removes the web/dev-dist/ directory containing auto-generated workbox 7.3.0 files that have two HIGH severity ReDoS vulnerabilities flagged by Snyk Code (SAST):

  • Line 949: Unsanitized user input from document location flows into match, used to build a regular expression
  • Line 4064: Unsanitized user input from request URL flows into match, used to build a regular expression

These files were generated by vite-plugin-pwa, which is no longer configured in the project — it is absent from web/package.json and web/vite.config.ts, and no source code in web/src/ references the dev-dist files. The directory is now added to .gitignore to prevent future re-commits of auto-generated PWA artifacts.

Files changed: .gitignore (added dev-dist/ pattern), deleted 3 files under web/dev-dist/ (~4,646 lines removed).

Review & Testing Checklist for Human

  • Verify that web/index.html does not reference registerSW.js, dev-sw.js, or any service worker registration that would break without dev-dist/
  • Confirm vite-plugin-pwa is intentionally removed from the project (it still appears in pnpm-lock.yaml as an orphan — consider running pnpm prune or removing it from the lockfile)
  • Run pnpm dev and confirm the dev server starts without errors or 404s related to missing service worker files

Notes

  • Build (pnpm build:web) and type-check (pnpm type-check) both pass cleanly after this change.
  • vite-plugin-pwa remains as a stale entry in pnpm-lock.yaml. This is harmless but could be cleaned up separately.

Link to Devin session: https://app.devin.ai/sessions/c9af95630ace4a2ca678e410fc7e358f
Requested by: @joao-cognition

Remove web/dev-dist/ directory containing auto-generated workbox 7.3.0
files with two HIGH severity ReDoS vulnerabilities (Snyk SAST):
- Line 949: unsanitized user input from document location flows into regex match
- Line 4064: unsanitized user input from request URL flows into regex match

The vite-plugin-pwa plugin that generated these files is no longer
configured in the project (not in web/package.json or vite.config.ts),
making dev-dist/ stale dead code. Added dev-dist/ to .gitignore to
prevent future commits of auto-generated PWA artifacts.

Co-Authored-By: Joao Esteves <joao.esteves@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
…(per-account login lockout)

Closes the two medium-severity findings the manual review surfaced.

Fix COG-GTM#4 — CWE-346 (Origin Validation Error)
- collaboration/index.ts: setupCollaboration() now takes corsOrigin and
  rejects browser-issued WS upgrades whose Origin header isn't on the
  allow-list. Same allow-list as the HTTP cors() middleware (one source
  of truth). Missing Origin (server-side clients) still allowed.
- index.ts: pass CORS_ORIGIN through.
- shipshape/security/modules/websocket.mjs: two new probe checks
  (ws-collab-rejects-evil-origin, ws-events-rejects-evil-origin). Local
  probe run confirms both return 'ok'.

Fix COG-GTM#5 — CWE-307 (Improper Restriction of Excessive Authentication Attempts)
- routes/auth.ts: in-memory per-email failure counter with 10 failures /
  15 min window. Triggers 429 RATE_LIMITED regardless of password
  correctness. Cleared on successful login.
- routes/auth.test.ts: 3 new tests prove (a) lockout fires after 10
  failures from a single IP, (b) correct password still rejected while
  locked out, (c) email match is case-insensitive.

Docs:
- shipshape/improvements/08-security.md: result table 3 -> 5 fixes; added
  full Fix COG-GTM#4 + Fix COG-GTM#5 sections (class, repro, fix, evidence, no-tests-
  broken).
- shipshape/security/MANUAL_REVIEW.md: both medium findings marked
  resolved with crosslinks to the fix sections.

Verification:
- pnpm type-check across api/web/shared: 0 errors.
- pnpm --filter @ship/api test: 454/454 pass (28 files), up from 451 baseline.
- node shipshape/security/probe.mjs: critical=0 maintained; the two new
  evil-origin probe IDs both 'ok'. Raw in raw-08sec-after-v2/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
…(per-account login lockout)

Closes the two medium-severity findings the manual review surfaced.

Fix COG-GTM#4 — CWE-346 (Origin Validation Error)
- collaboration/index.ts: setupCollaboration() now takes corsOrigin and
  rejects browser-issued WS upgrades whose Origin header isn't on the
  allow-list. Same allow-list as the HTTP cors() middleware (one source
  of truth). Missing Origin (server-side clients) still allowed.
- index.ts: pass CORS_ORIGIN through.
- shipshape/security/modules/websocket.mjs: two new probe checks
  (ws-collab-rejects-evil-origin, ws-events-rejects-evil-origin). Local
  probe run confirms both return 'ok'.

Fix COG-GTM#5 — CWE-307 (Improper Restriction of Excessive Authentication Attempts)
- routes/auth.ts: in-memory per-email failure counter with 10 failures /
  15 min window. Triggers 429 RATE_LIMITED regardless of password
  correctness. Cleared on successful login.
- routes/auth.test.ts: 3 new tests prove (a) lockout fires after 10
  failures from a single IP, (b) correct password still rejected while
  locked out, (c) email match is case-insensitive.

Docs:
- shipshape/improvements/08-security.md: result table 3 -> 5 fixes; added
  full Fix COG-GTM#4 + Fix COG-GTM#5 sections (class, repro, fix, evidence, no-tests-
  broken).
- shipshape/security/MANUAL_REVIEW.md: both medium findings marked
  resolved with crosslinks to the fix sections.

Verification:
- pnpm type-check across api/web/shared: 0 errors.
- pnpm --filter @ship/api test: 454/454 pass (28 files), up from 451 baseline.
- node shipshape/security/probe.mjs: critical=0 maintained; the two new
  evil-origin probe IDs both 'ok'. Raw in raw-08sec-after-v2/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
…verified post-cherry-pick

Both new checks (prod-ws-collab-rejects-evil-origin,
prod-ws-events-rejects-evil-origin) return ok against Render. All 12 prod
verification checks ok; Fix COG-GTM#1 (WS error handler) confirmed live via
"API alive after WS probes"; Fix COG-GTM#3 (body-parser stack-leak) confirmed
live via sanitized 400 envelope. Fix COG-GTM#4 code is definitively deployed
in commit 61862d7; an authenticated-cookie + evil-Origin upgrade would
isolate the Origin check from the auth check but requires production
credentials.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
…link from SUBMISSION

- discoveries.md: add Discovery COG-GTM#4 — Ship's REST/CRDT bridge in
  api/src/collaboration/index.ts. Three coordinated pieces: a one-shot
  Set<string> tracking which docs were last written via REST, a synthetic
  Yjs `messageClearCache = 3` frame sent before sync handshake, and
  schedulePersist() writing the converted state back as yjs_state. The
  pattern is the bug every "we'll add CRDT collab later" project hits.
  Reusable parts: source-of-truth rotation signaling, inventing a
  protocol message vs. piggybacking on close codes, one-shot ephemeral
  state with explicit deletion.
- SUBMISSION.md: expand the Discovery row to surface direct anchor links
  to each of the four discoveries so a reviewer can deep-link without
  scrolling.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
…raform for Vercel+Render+Neon

The SUBMISSION's honest hedge noted I hadn't touched Docker or Terraform
during the audit/improvement phase because the actual deploy went to
Vercel + Render + Neon, not the Treasury AWS path the existing terraform/
encodes. This commit fills that gap with two parallel pieces.

docker-compose.prod-mirror.yml
- Exercises the multi-stage Dockerfile (the same image Render builds + runs),
  not the dev Dockerfile that docker-compose.local.yml already uses.
- Postgres 16 pinned to mirror Neon's version exactly.
- Env vars match what Render sets in production, including the Cat 8
  Fix COG-GTM#4 CORS_ORIGIN (read by the WS Origin allow-list) and the
  COOKIE_SAMESITE=none cross-origin setup from commit 14522db.
- Provides a one-command end-to-end smoke test of the prod image without
  needing a Render account.

terraform/render-vercel-neon/
- versions.tf — provider pins for render-oss/render ~> 1.4, vercel/vercel
  ~> 2.0, kislerdm/neon ~> 0.6.
- main.tf — codifies the three previously-manual dashboard configs:
    neon_project + branch + role + database (Postgres 16),
    render_web_service (multi-stage Dockerfile, auto-deploy off
      shipshape/deploy, env vars including Cat 8 Fix COG-GTM#4 CORS_ORIGIN),
    vercel_project (Vite preset, VITE_API_URL pointing at Render),
    vercel_project_domain (defaults to project.vercel.app).
  Apply order enforced by depends_on: Neon → Render → Vercel.
- variables.tf — required provider credentials + sensible defaults for
  project name, branch, regions, CORS origin. session_secret auto-
  generates a 64-char hex string when empty.
- outputs.tf — web_url, api_url, neon_project_id, database_url
  (sensitive), and a verify_prod_command output that returns a ready-to-
  run `node shipshape/security/verify-prod.mjs --api=... --web=...`
  invocation against the freshly-provisioned URLs.
- README.md — usage, what's intentionally NOT in there, drift detection,
  verification via verify-prod.mjs, secrets handling. Includes an honest
  hedge enumerating the three leaf-attribute names most likely to need
  surgical adjustment on first apply.

.gitignore
- Added rules for terraform/render-vercel-neon/{.terraform/,*.tfvars,
  *.tfstate,*.tfstate.backup,.terraform.lock.hcl} so provider creds and
  state never accidentally get committed.

shipshape/SUBMISSION.md + AT_A_GLANCE.md
- Deployed-application deliverable cells now cross-link to the new
  Terraform module and prod-mirror compose.
- SUBMISSION Honest Hedges section gains a new bullet calling out that
  the Terraform module was not `terraform init` + `terraform validate`-
  tested in this session because no Terraform binary was on the workstation.
  README "Honest hedge — provider attribute shapes" section enumerates the
  three leaf attributes most likely to need adjustment.

The existing AWS terraform/ tree (Elastic Beanstalk + CloudFront + RDS)
is untouched — this is a parallel module for the actually-deployed stack,
not a replacement for the Treasury production path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
… checks pass at 2026-05-22T20:25Z

Sanity check after the terraform apply→destroy cycle (against a
separate ship-shipshape namespace, parallel to live ship-henna) to
confirm nothing on the existing live deploy regressed. All twelve
Cat 8 checks come back green against the production URLs.

- ship-api-76ez.onrender.com /health → 200
- ship-henna.vercel.app / → 200
- All required hardening headers present
- CORS preflight rejects evil origin, allows prod origin
- Malformed JSON gets the sanitized VALIDATION_ERROR envelope (no stack leak)
- All 3 WS endpoints reject unauthenticated handshakes (events, collaboration, unknown)
- /collaboration + /events WS with evil Origin (Fix COG-GTM#4) both rejected at handshake
- API stays healthy after WS upgrade abuse attempts (no crash)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tylerxia8 added a commit to tylerxia8/ship that referenced this pull request May 22, 2026
…s pass

The Docker hedge moves from its previous "static checks pass, runtime
deferred (WSL disk exhaustion)" state to its strongest possible
state: "docker compose -f docker-compose.prod-mirror.yml up --build
succeeded against a fresh empty docker_data.vhdx; postgres:16 +
multi-stage api containers came up healthy; 5/5 Cat 8 protections
verified active in the production code path."

Disk recovery to make this possible:
- Deleted gitignored .terraform/ provider cache (~310 MB)
- Stopped Docker Desktop, ran `wsl --shutdown`, deleted
  docker_data.vhdx (~22 GB) — fresh empty VHDX on Docker restart

Build + run + verify cycle:
- Build: ~2-3 min from empty cache (node:20-slim pull, pnpm install,
  tsc, prod-only deps install, final slim image)
- Up: postgres-1 healthy in <10s, api-1 serving /health in <15s
- Smoke tests (all passing):
  1. /health → 200 in 6ms
  2. POST /api/issues with malformed JSON → 400 with the Cat 8 Fix COG-GTM#3
     sanitized envelope {success:false, error:{code, message}}, no
     stack leak
  3. CORS preflight from https://evil.example.com → 204 with
     Access-Control-Allow-Origin: http://localhost:5173 (the prod
     origin, NOT the evil one — browser would block)
  4. All hardening headers present on /health response (CSP, HSTS
     with preload, X-Content-Type-Options, X-Frame-Options, COOP,
     COR-Policy, Referrer-Policy, plus Cat 8 Fix COG-GTM#2 rate-limit
     headers RateLimit-Policy: 100;w=60)
  5. WS handshake from evil origin to /collaboration/issue:test
     → 403 Forbidden (Cat 8 Fix COG-GTM#4 working in prod build)

One known prod-mirror divergence documented in the evidence file:
the migration step fails with "server does not support SSL
connections" because Postgres 16's default image doesn't enable SSL
but Ship's pool config defaults to ?sslmode=require (matches the
Render/Neon prod path). The CMD's diagnostic phase= prints surface
exactly this, and the server starts anyway because the CMD uses ;
not && — failure is observable + recoverable, not silent.

Cleanup: docker compose down -v completed, all containers/volumes
gone. The ship-api:latest image stays cached for re-runs.

Evidence file:
shipshape/security/raw-prod/docker-prod-mirror-smoke-2026-05-22.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

0 participants