Add test and security baseline
- make quick/check/mutation from cj/security-baseline (Makefile unchanged, settings in baseline.mk), pre-commit, gitleaks, Semgrep rules, ESLint security rules, Forgejo workflow - tests/security: generic baseline tests plus app config and role tests against createApp() with an in-memory database - extract createApp() from src/server/index.ts; LB_DATABASE_PATH for tests - fix gaps found by the tests: reject unknown fields on project create, answer malformed JSON with 400 instead of 500, set nosniff on the API - npm audit fix (next 16.4.1 and others, no high/critical left) - clear ESLint errors, safeFileName without control-character regex - per-project ownership stays an open, documented gap (idorGap -> TODO) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
67476ea59b
commit
a7a1595cbf
38 changed files with 5852 additions and 442 deletions
76
.semgrep/typescript.yml
Normal file
76
.semgrep/typescript.yml
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
rules:
|
||||
- id: react-dangerously-set-inner-html
|
||||
languages: [typescript, javascript]
|
||||
severity: ERROR
|
||||
message: dangerouslySetInnerHTML ist ein XSS-Einfallstor. Text rendern oder mit DOMPurify säubern.
|
||||
pattern-either:
|
||||
- pattern: <$EL dangerouslySetInnerHTML={...} />
|
||||
- pattern: <$EL dangerouslySetInnerHTML={...}>...</$EL>
|
||||
- pattern: "{dangerouslySetInnerHTML: ...}"
|
||||
|
||||
- id: dom-inner-html
|
||||
languages: [typescript, javascript]
|
||||
severity: ERROR
|
||||
message: innerHTML/outerHTML/insertAdjacentHTML mit dynamischem Inhalt (XSS). textContent verwenden.
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $EL.innerHTML = $V
|
||||
- pattern: $EL.outerHTML = $V
|
||||
- pattern: $EL.insertAdjacentHTML($POS, $V)
|
||||
- pattern: document.write($V)
|
||||
- pattern-not: $EL.innerHTML = "..."
|
||||
- pattern-not: $EL.innerHTML = ``
|
||||
|
||||
- id: token-in-web-storage
|
||||
languages: [typescript, javascript]
|
||||
severity: WARNING
|
||||
message: Token/Secret im Web Storage ist per XSS auslesbar. HttpOnly-Cookie verwenden.
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: localStorage.setItem($K, ...)
|
||||
- pattern: sessionStorage.setItem($K, ...)
|
||||
- pattern: window.localStorage.setItem($K, ...)
|
||||
- metavariable-regex:
|
||||
metavariable: $K
|
||||
regex: (?i).*(token|jwt|secret|auth|session|password|api.?key).*
|
||||
|
||||
- id: express-cors-wildcard
|
||||
languages: [typescript, javascript]
|
||||
severity: ERROR
|
||||
message: CORS erlaubt jede Origin (bei credentials besonders gefährlich). Origins explizit auflisten.
|
||||
pattern-either:
|
||||
- pattern: cors()
|
||||
- pattern: 'cors({..., origin: "*", ...})'
|
||||
- pattern: 'cors({..., origin: true, ...})'
|
||||
- pattern: $RES.setHeader("Access-Control-Allow-Origin", "*")
|
||||
- pattern: $RES.header("Access-Control-Allow-Origin", "*")
|
||||
|
||||
- id: sql-template-string
|
||||
languages: [typescript, javascript]
|
||||
severity: ERROR
|
||||
message: SQL per Template-String oder Verkettung. Platzhalter/Query-Builder verwenden.
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $DB.$M(`...${$X}...`, ...)
|
||||
- pattern: $DB.$M("..." + $X, ...)
|
||||
- pattern: sql.raw(`...${$X}...`)
|
||||
- pattern: sql.raw("..." + $X)
|
||||
- metavariable-regex:
|
||||
metavariable: $M
|
||||
regex: ^(query|exec|execute|prepare|run|all|get|raw|\$queryRawUnsafe|\$executeRawUnsafe)$
|
||||
|
||||
- id: tls-verification-disabled-node
|
||||
languages: [typescript, javascript]
|
||||
severity: ERROR
|
||||
message: TLS-Zertifikatsprüfung abgeschaltet.
|
||||
pattern-either:
|
||||
- pattern: "{..., rejectUnauthorized: false, ...}"
|
||||
- pattern: process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
||||
|
||||
- id: jwt-decode-without-verify
|
||||
languages: [typescript, javascript]
|
||||
severity: ERROR
|
||||
message: jwt.decode prüft keine Signatur. jwt.verify verwenden.
|
||||
pattern-either:
|
||||
- pattern: jwt.decode(...)
|
||||
- pattern: 'jwt.verify($T, $K, {..., algorithms: [..., "none", ...], ...})'
|
||||
Loading…
Add table
Add a link
Reference in a new issue