SEC2-042: The dedicated CSP browser test overrides the real policy with a stale hand copy #984

Closed
opened 2026-10-17 10:39:16 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-10-16 in a read-only security review of postulo at 56fc9d531, checked by a second, independent pass.

Severity: Informational · Category: Configuration · Reference: CWE-1059 (Insufficient Technical Documentation); OWASP A05:2021 (Security Misconfiguration)

Location:

  • tests/e2e/test_csp.py:23-39 (strict_csp fixture) and :56-130 (the pages it visits)
  • src/postulo/config/settings/base.py:818-851 (the policy it claims to copy)

Issue

The fixture says "Exactly what config/settings/prod.py sends" and then writes its own dictionary:

settings.SECURE_CSP = {
    "default-src": [CSP.NONE], "script-src": [CSP.SELF], "style-src": [CSP.SELF],
    "img-src": [CSP.SELF, "data:"], "font-src": [CSP.SELF], "connect-src": [CSP.SELF],
    "form-action": [CSP.SELF], "frame-ancestors": [CSP.NONE], "base-uri": [CSP.SELF],
}

The real policy has style-src 'self' 'nonce-…', base-uri 'none', worker-src, manifest-src, frame-src 'self', object-src 'none', the OIDC form-action origins and report-uri. The four tests therefore run under a different policy from production, and the pages they visit do not include the two exceptions (the framed CV/letter preview with its nonce, the map page with its tile origin).

The production policy is exercised elsewhere: tests/e2e/conftest.py:336-370 has an autouse fixture that runs every browser test under settings.SECURE_CSP and fails on any reported violation, and tests/security/test_requests.py:203-204 already asserts the policy carries no unsafe-inline or unsafe-eval and no third-party origin. So the gap is the test named for the CSP, not the coverage.

Impact

No exploit; a misleading test. The file is the one a reviewer reads to learn what the CSP test proves.

Fix

Delete the strict_csp override (the autouse fixture already enforces the real policy), or derive it from settings.SECURE_CSP, and correct the docstring; optionally add /jobs/companies/map/ and a preview frame to the visited pages. Done when: tests/e2e/test_csp.py holds no directive literals and still passes.

#232 (closed) - introduced the test. #822 (closed) - the CSP hardening (base-uri, reporting) that made the copy stale.

Found on 2026-10-16 in a read-only security review of `postulo` at `56fc9d531`, checked by a second, independent pass. **Severity:** Informational · **Category:** Configuration · **Reference:** CWE-1059 (Insufficient Technical Documentation); OWASP A05:2021 (Security Misconfiguration) **Location:** - `tests/e2e/test_csp.py:23-39` (`strict_csp` fixture) and `:56-130` (the pages it visits) - `src/postulo/config/settings/base.py:818-851` (the policy it claims to copy) ## Issue The fixture says "Exactly what `config/settings/prod.py` sends" and then writes its own dictionary: ```python settings.SECURE_CSP = { "default-src": [CSP.NONE], "script-src": [CSP.SELF], "style-src": [CSP.SELF], "img-src": [CSP.SELF, "data:"], "font-src": [CSP.SELF], "connect-src": [CSP.SELF], "form-action": [CSP.SELF], "frame-ancestors": [CSP.NONE], "base-uri": [CSP.SELF], } ``` The real policy has `style-src 'self' 'nonce-…'`, `base-uri 'none'`, `worker-src`, `manifest-src`, `frame-src 'self'`, `object-src 'none'`, the OIDC `form-action` origins and `report-uri`. The four tests therefore run under a different policy from production, and the pages they visit do not include the two exceptions (the framed CV/letter preview with its nonce, the map page with its tile origin). The production policy is exercised elsewhere: `tests/e2e/conftest.py:336-370` has an autouse fixture that runs every browser test under `settings.SECURE_CSP` and fails on any reported violation, and `tests/security/test_requests.py:203-204` already asserts the policy carries no `unsafe-inline` or `unsafe-eval` and no third-party origin. So the gap is the test named for the CSP, not the coverage. ## Impact No exploit; a misleading test. The file is the one a reviewer reads to learn what the CSP test proves. ## Fix Delete the `strict_csp` override (the autouse fixture already enforces the real policy), or derive it from `settings.SECURE_CSP`, and correct the docstring; optionally add `/jobs/companies/map/` and a preview frame to the visited pages. Done when: `tests/e2e/test_csp.py` holds no directive literals and still passes. ## Related #232 (closed) - introduced the test. #822 (closed) - the CSP hardening (`base-uri`, reporting) that made the copy stale.
tiagoagueda added this to the 1.0.0 milestone 2026-10-17 10:39:18 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#984
No description provided.