diff --git a/audits/20260810-1611-functionalityNextSteps.md b/audits/20260810-1611-functionalityNextSteps.md new file mode 100644 index 0000000..c654de7 --- /dev/null +++ b/audits/20260810-1611-functionalityNextSteps.md @@ -0,0 +1,53 @@ +# Functionality and Next Steps Report + +## 1. Executive Summary + +Relata is a well-structured Go modular monolith with explicit service/repository boundaries, deterministic fallbacks, useful operational documentation, and broad race-enabled tests. The highest-value next work is to make expensive-work admission explicit, shorten and isolate integration tests, improve browser-level coverage, and make backup/deployment artifacts reproducible. The audit fixes also improved token UX safety, malformed-input behavior, error privacy, file permissions, and clipboard feedback. + +## 2. Current Functional Risks + +- The security integration suite takes about 8½ minutes and shares MongoDB/Qdrant. Concurrent suite runs exhausted Qdrant file resources and left test collections, making local/CI feedback fragile. +- Rendering a one-time token directly after POST prevents URL disclosure, but refreshing that page can prompt a form resubmission and create a second token. A server-side one-time flash/nonce flow would preserve Post/Redirect/Get without putting credentials in the URL. +- Upload, embedding, analysis, and answer operations have local limits but no unified per-workspace capacity budget; one busy tenant can increase latency for others. +- The backup script creates private files but does not provide encryption, checksums, retention, or an automated restore verification. +- Production operation depends on nginx, systemd, `/etc/relata/relata.env`, and host Ollama behavior that cannot be validated by repository tests alone. + +## 3. Code Quality Improvements + +Centralize pagination normalization so browser lists, API lists, and search use the same typed parser and invariant tests. Introduce stable public/internal error classes at parser, model, and job boundaries so logs and persisted failures remain useful without carrying raw dependency messages. Split integration harness setup into suite-scoped infrastructure plus per-test logical isolation to reduce repeated collection/index creation. Keep security-sensitive helpers—token display, PHC decoding, principal/workspace filters—small and directly testable. + +## 4. Frontend Interaction and Error-Handling Improvements + +The clipboard handler now handles absent sources, unavailable API, and rejected writes without logging the bearer value. Add an accessible `aria-live` status element instead of temporarily changing only button text, preserve focus across HTMX swaps, and test keyboard-only token creation/revocation. Add a browser-level assertion that CSRF headers survive HTMX requests and that no token reaches URL, history, referrer, console, or analytics. Update the vendored HTMX asset through a documented checksum-based process. + +## 5. Testing Roadmap + +1. Add focused service tests for every pagination boundary and hostile PHC value; retain the new panic/token regressions. +2. Add Playwright or equivalent browser tests for login, upload, token lifecycle, clipboard failure/success, HTMX navigation, CSP, and accessibility. +3. Make integration resources suite-scoped or serialize targets with an explicit lock; always remove stale `relata_test_*` stores on controlled startup/cleanup. +4. Add concurrent queue/admission, lease-expiry, cancellation, model timeout, and bounded-load tests. +5. Add deployment smoke tests with authenticated datastores and a backup-create/restore/checksum drill. +6. Run fuzz targets for PHC parsing, PDFs, mail/HTML parsing, filter normalization, and model schema responses in scheduled CI. + +## 6. Recommended New Functionality + +- **Workspace capacity controls:** configurable queued/active job, upload-byte, stored-byte, and model-request budgets with clear `429`/`503` feedback. +- **One-time credential handoff:** server-side encrypted or in-memory single-use flash storage keyed by a short-lived nonce, allowing safe redirect-after-POST without replaying token creation. +- **Backup lifecycle tooling:** encrypted streaming output, manifest/checksums, retention pruning, Qdrant/Mongo/upload consistency metadata, and a non-destructive restore verifier. +- **Session and token management:** display active sessions, last token use, suspicious-use events, and one-click revocation/rotation while never storing raw tokens. +- **Operational readiness view:** queue depth, oldest job, failed/retried jobs, model/datastore latency, storage use, and dependency health by workspace-safe aggregates. + +## 7. Next-Level Opportunities + +Generate an SBOM and signed provenance for images, pin production digests, and automate dependency/vendor update pull requests. Add OpenTelemetry-compatible traces with strict attribute allowlists. Consider separate worker deployment and independently scalable queues once workload evidence justifies the operational cost. Improve accessibility through automated axe checks and manual keyboard/screen-reader testing. Maintain a compatibility matrix for MongoDB, Qdrant, Ollama models, and embedding dimensions to make upgrades and restores predictable. + +## 8. Prioritised Action Plan + +- **Immediate:** ship the audited fixes, rotate historically URL-exposed tokens, document sequential integration execution, and encrypt off-host backups. +- **Short term:** remove test-harness resource churn, add browser tests, implement workspace admission/queue limits, pin images, and record HTMX provenance. +- **Medium term:** add datastore authentication, automated restore drills, SBOM/provenance checks, operational dashboards/alerts, and server-side one-time token flash delivery. +- **Long term:** evaluate split worker scaling, richer session/security management, cross-service tracing, and multi-tenant performance objectives based on observed production demand. + +## 9. Caveats and Validation Needed + +Priorities assume Relata may host sensitive, multi-user knowledge and that authenticated abuse matters. Validate expected tenant count, upload volume, model capacity, recovery-time/recovery-point objectives, and operator tolerance before choosing quota defaults or new infrastructure. Browser behavior, OAuth providers, nginx/systemd configuration, datastore-auth compatibility, backup encryption keys, and production load all need runtime validation. The repository was almost entirely untracked at audit start, so commits of fixed files record those whole files rather than a conventional baseline diff. diff --git a/audits/20260810-1611-securityAudit.md b/audits/20260810-1611-securityAudit.md new file mode 100644 index 0000000..e4fbe2a --- /dev/null +++ b/audits/20260810-1611-securityAudit.md @@ -0,0 +1,545 @@ +# Security Audit Report + +## 1. Executive Summary + +Relata has a generally strong security baseline: workspace scoping is pervasive, authentication uses Argon2id and constant-time comparisons, untrusted bodies and document parsing are bounded, templates escape output, CSRF and CSP controls are present, and the production application container is non-root, capability-free, and read-only. This audit confirmed one high-risk credential disclosure path and four medium/low issues; all five were fixed with regression tests. No critical issue, remote-code-execution path, authorization bypass, hard-coded production credential, or reachable vulnerable Go dependency was found. + +Residual risk is concentrated in authenticated resource abuse, floating container tags and vendored frontend provenance, and unauthenticated plaintext datastore traffic inside the private Compose network. Those items require operational or architectural decisions beyond a safe local patch. + +## 2. Scope Reviewed + +Reviewed the Go application under `cmd/` and `internal/`, HTML templates and JavaScript under `internal/web/`, unit and integration tests, `go.mod`/`go.sum`, Dockerfile and Compose definitions, deployment documentation, migrations, backup scripts, and environment examples. Entry points included browser sessions, OAuth/OIDC, API bearer tokens, uploads, search/answer endpoints, background jobs, MongoDB, Qdrant, and Ollama. The real `.env` contents and `/etc/relata/relata.env` were deliberately not read. + +## 3. Methodology + +The review combined manual data-flow and authorization tracing, adversarial attack-surface mapping, configuration and dependency review, cryptography and secret-lifecycle analysis, panic/error-path inspection, memory and DoS analysis, frontend event review, and negative-test review. Verification used `make check`, `make test-security`, focused regressions, `go mod verify`, `govulncheck`, shell/JavaScript syntax checks, and Docker Compose validation. Malformed inputs were assessed with bounded tests; no destructive load testing or live exploit against production was performed. + +## 4. Risk Rating Method + +Severity combines exploitability, required privilege, affected confidentiality/integrity/availability, and blast radius. Confidence reflects evidence quality and runtime confirmation. `Fixed` means the remediation and a proportionate regression test passed during this audit; `Open` means a decision or further work remains. + +## 5. Attack Surface Map + +- **Internet/browser boundary:** nginx is expected to terminate TLS and proxy to the loopback-only Go HTTP service. Browser routes accept credentials, OAuth/OIDC callbacks, forms, and uploads. +- **API boundary:** `/api/v1/*` accepts session or scoped bearer-token authentication, JSON, filters, pagination, search, and answer requests. +- **Processing boundary:** uploaded PDF, text, HTML, email, and archive-like content flows through parsers, chunking, embeddings, analysis, and leased background jobs. +- **Data boundary:** MongoDB stores identities, sessions, token hashes, documents, jobs, and audit events; Qdrant stores workspace-tagged vectors; upload volumes retain originals. +- **External integrations:** OAuth/OIDC issuers, Qdrant, MongoDB, and Ollama/model responses are separate trust boundaries. +- **Starting positions:** anonymous network client, authenticated member, scoped API-token holder, malicious document author, compromised model/service, compromised database, or local host/container operator. + +## 6. Findings Summary Table + +| ID | Severity | Confidence | Title | Component | Status | +|---|---|---|---|---|---| +| SEC-001 | High | High | One-time API token disclosed through redirect URL | Web token creation | Fixed | +| SEC-002 | Medium | High | Negative search offset could panic request handling | API/search pagination | Fixed | +| SEC-003 | Medium | High | Stored Argon2 parameters permitted extreme resource requests | Password verification | Fixed | +| SEC-004 | Medium | High | Local secrets and backups inherited permissive file modes | Setup/backup operations | Fixed | +| SEC-005 | Low | High | Panic values could disclose sensitive input in logs or job records | HTTP, jobs, PDF parsing | Fixed | +| SEC-006 | Medium | Medium | Authenticated expensive-work controls are incomplete | Upload/search/job pipeline | Open | +| SEC-007 | Low | High | Deployments are not fully reproducible or provenance-pinned | Containers/frontend vendor asset | Open | +| SEC-008 | Low | Medium | Internal datastores rely primarily on network isolation | MongoDB/Qdrant transport and auth | Open | + +## 7. Detailed Findings + +### Finding ID: SEC-001 + +#### Title + +One-time API token disclosed through redirect URL + +#### Severity + +High + +#### Confidence + +High + +#### Affected Files / Components + +`internal/web/tokens.go:43-46,97-136`, `internal/web/templates/tokens.html`, route `POST /settings/tokens`. + +#### Description + +Token creation previously redirected to a URL containing the complete bearer secret in query parameters. URLs commonly enter browser history, reverse-proxy/access logs, monitoring, screenshots, and referrer data. Possession of the secret grants its configured API scopes until revocation or expiry. + +#### Evidence + +The fixed handler renders the secret only in the `201 Created` POST response and does not emit a `Location` header. `internal/web/tokens_test.go:63-101` verifies both that creation never redirects with a secret and that attacker-supplied `?secret=` input is ignored. + +#### Attack Scenario + +An administrator creates an automation token. A party with access to browser history or URL logs extracts `rlt_v1_...` and uses it against API routes within the token's scopes. + +#### Impact + +Unauthorized reading or mutation of workspace data, bounded by token scopes and lifetime. + +#### Recommendation + +Implemented: keep one-time credentials out of URLs and render them once in the direct authenticated response. Continue redacting authorization headers and token-shaped values in all telemetry. + +#### Safer Example + +`h.renderTokensPage(w, r, principal, issued.Secret, issued.Token.Name, http.StatusCreated)` with no redirect or query serialization. + +#### Suggested Tests + +Retain the redirect/query regressions and add a browser test confirming history and referrer data never contain the token. + +#### References + +CWE-598; OWASP ASVS V9 (communications) and V8 (data protection). + +#### Assumptions / Limitations + +Existing logs or history may retain tokens created before this fix. Operators should rotate any such token if URL logging was enabled. + +### Finding ID: SEC-002 + +#### Title + +Negative search offset could panic request handling + +#### Severity + +Medium + +#### Confidence + +High + +#### Affected Files / Components + +`internal/api/handlers.go:991-1003`, `internal/search/search.go:145-163`, authenticated search endpoint. + +#### Description + +A negative `offset` survived query parsing and could become a negative slice start during result paging. The recovery middleware converted the panic to HTTP 500, but repeated authenticated requests could consume CPU, generate error traffic, and degrade availability. + +#### Evidence + +The API now accepts only positive offsets and the service independently clamps negatives to zero. `internal/api/http_test.go:462-470` covers the hostile query. + +#### Attack Scenario + +A valid user or leaked query-scoped token repeatedly calls search with `offset=-7`, forcing panic recovery on otherwise successful searches. + +#### Impact + +Request-level denial of service, noisy logs, and possible service degradation under repetition; no memory disclosure was observed. + +#### Recommendation + +Implemented: normalize at both transport and service boundaries. Apply the same invariant to every future pagination entry point. + +#### Safer Example + +`offset := q.Offset; if offset < 0 { offset = 0 }` before constructing the response or slicing. + +#### Suggested Tests + +Retain API and service boundary tests for negative, zero, maximum, and overflow-like pagination values. + +#### References + +CWE-129; CWE-400; OWASP API Security API4:2023. + +#### Assumptions / Limitations + +Exploitation requires an authenticated principal because search is not anonymous. + +### Finding ID: SEC-003 + +#### Title + +Stored Argon2 parameters permitted extreme resource requests + +#### Severity + +Medium + +#### Confidence + +High + +#### Affected Files / Components + +`internal/auth/password.go:29-44,123-189`, password login against stored PHC hashes. + +#### Description + +The verifier trusted memory, iteration, parallelism, salt, and output sizes encoded in a stored hash. A database write compromise or corrupt record could request gigabytes of memory or excessive CPU at the next login, extending a database incident into application-host denial of service. + +#### Evidence + +The decoder now limits the encoded string to 512 bytes, memory to 256 MiB, iterations to 10, parallelism to 16, salt to 16-64 bytes, and key to 16-64 bytes. Malformed-hash tests at `internal/auth/auth_test.go:78-93` include excessive memory, time, and size. + +#### Attack Scenario + +An attacker with a database write primitive changes a user's PHC parameters, then submits that username to trigger expensive verification. + +#### Impact + +Memory exhaustion, CPU saturation, or process termination during login. + +#### Recommendation + +Implemented: treat stored parameters as untrusted instructions and reject values outside an upgrade-compatible policy. Alert on invalid stored hashes. + +#### Safer Example + +Validate all parsed PHC fields before calling `argon2.IDKey`; never allocate based on unchecked stored values. + +#### Suggested Tests + +Keep table and fuzz tests; add a metric/assertion that invalid hashes terminate without invoking Argon2. + +#### References + +CWE-400; OWASP ASVS V2.4. + +#### Assumptions / Limitations + +The primary prerequisite is database modification or corruption. The selected 256 MiB ceiling remains intentionally expensive and should be considered in host concurrency limits. + +### Finding ID: SEC-004 + +#### Title + +Local secrets and backups inherited permissive file modes + +#### Severity + +Medium + +#### Confidence + +High + +#### Affected Files / Components + +`Makefile:40-49`, `scripts/backup.sh:16-30`, `.gitignore`, `.dockerignore`, local `.env`. + +#### Description + +Setup and backup creation previously inherited the caller's umask. On a common `022` configuration, `.env` and complete knowledge-store archives could be group/world readable. Backup output may include documents and personal data. + +#### Evidence + +Setup now applies mode `0600`; backup execution sets `umask 077`; backup directories/files were dynamically verified as `0700`/`0600` under caller umask `022`; generated backups are excluded from Git and Docker build contexts. The existing `.env` was changed from `0644` to `0600` without reading its contents. + +#### Attack Scenario + +Another local account or process reads a newly generated environment file or backup archive from a shared host. + +#### Impact + +Credential disclosure and bulk compromise of stored documents and metadata. + +#### Recommendation + +Implemented for file modes. Additionally encrypt backups before off-host transfer, restrict backup service identities, define retention, and test restoration. + +#### Safer Example + +Run `umask 077` before `mkdir`, `mongodump`, and archive creation; explicitly `chmod 600 .env` after copying the example. + +#### Suggested Tests + +Add a shell smoke test under umask `022` that asserts exact output modes and a restore drill that checks encrypted archive integrity. + +#### References + +CWE-732; CWE-312; OWASP ASVS V8. + +#### Assumptions / Limitations + +POSIX modes do not protect against root, the same account, host compromise, snapshots, or unencrypted off-host copies. + +### Finding ID: SEC-005 + +#### Title + +Panic values could disclose sensitive input in logs or job records + +#### Severity + +Low + +#### Confidence + +High + +#### Affected Files / Components + +`internal/api/middleware.go:155-169`, `internal/jobs/worker.go:258-268`, `internal/parsing/pdf.go:30-39`. + +#### Description + +Recovered panic values were logged or converted to persistent job errors. Panic strings from application or third-party parsing code can include credentials, document fragments, or attacker-controlled content. + +#### Evidence + +Recovery now records only stable context and generic errors. `internal/api/http_test.go:441-459` and `internal/jobs/worker_test.go:269-279` assert sentinel secrets do not reach responses, logs, or persistent errors. + +#### Attack Scenario + +A malformed document triggers a library panic whose value contains document text; the old worker path stored it with the failed job and emitted it to logs. + +#### Impact + +Secondary disclosure to log readers, support tooling, and job viewers. + +#### Recommendation + +Implemented: log correlation identifiers and stable error classes, never raw panic objects or sensitive payloads. Preserve stack traces only in a separately protected diagnostic channel if operationally necessary. + +#### Safer Example + +Return `errors.New("job handler panicked")` and log request path/method plus an existing request ID. + +#### Suggested Tests + +Retain sentinel-secret tests and add structured-log redaction checks for authorization headers and model/parser errors. + +#### References + +CWE-532; OWASP ASVS V7. + +#### Assumptions / Limitations + +This does not prove every ordinary non-panic error is free of sensitive third-party text; logging policy should remain conservative. + +### Finding ID: SEC-006 + +#### Title + +Authenticated expensive-work controls are incomplete + +#### Severity + +Medium + +#### Confidence + +Medium + +#### Affected Files / Components + +Upload, search/answer, embedding/analysis, and background-job paths under `internal/api/`, `internal/ingest/`, `internal/search/`, and `internal/jobs/`. + +#### Description + +Individual request sizes, parser work, retries, and worker counts are bounded, and API tokens have rate controls. However, there is no clearly enforced global or per-workspace budget spanning session-driven uploads, queued jobs, embeddings, and model-backed queries. A valid member can generate sustained expensive work within ordinary request limits. + +#### Evidence + +The code has useful local ceilings and bounded workers, but no unified admission-control counter or workspace quota was identified across the end-to-end pipeline. The threat model already identifies authenticated queue exhaustion as a limitation. + +#### Attack Scenario + +A compromised member session submits many maximum-allowed documents and model-backed queries, keeping workers and Ollama busy and delaying other tenants. + +#### Impact + +CPU, memory, disk, model capacity, and queue exhaustion; degraded availability and increased operating cost. + +#### Recommendation + +Add per-user/workspace concurrent-job limits, queue-depth ceilings, token-bucket admission controls, storage quotas, and operator alerts. Return `429`/`503` with retry guidance before accepting work that cannot be serviced safely. + +#### Safer Example + +Atomically reserve a workspace work unit before persisting a job; reject when `active + queued >= configured limit`, and release the reservation on every terminal path. + +#### Suggested Tests + +Add concurrent admission tests, queue saturation tests, cancellation/lease recovery tests, and bounded load tests using disposable stores. + +#### References + +CWE-400; OWASP API Security API4:2023. + +#### Assumptions / Limitations + +Practical severity depends on tenant trust, model capacity, reverse-proxy limits, and production rate controls not present in this repository. + +### Finding ID: SEC-007 + +#### Title + +Deployments are not fully reproducible or provenance-pinned + +#### Severity + +Low + +#### Confidence + +High + +#### Affected Files / Components + +`docker-compose.yml`, `deploy/docker-compose.prod.yml:21-65`, `internal/web/static/vendor/htmx.min.js:1`. + +#### Description + +MongoDB uses the mutable major tag `mongo:7`, development Ollama uses `latest`, and the application defaults to `relata:latest`; no image digests are recorded. Vendored HTMX identifies as 2.0.4 while the current upstream stable release observed during the audit was 2.0.9, and no checksum/provenance manifest documents the copied artifact. + +#### Evidence + +Compose files contain the mutable tags above. `govulncheck` found no reachable Go vulnerability; it reported only GO-2026-5932 in the unimported `x/crypto/openpgp` module package. `go mod verify` passed. The [official HTMX releases](https://github.com/bigskysoftware/htmx/releases) identify 2.0.9 as current; no upstream advisory was found, so the version gap is not classified as a known exploitable vulnerability. + +#### Attack Scenario + +A rebuild at a later date resolves a different image under the same tag, or an unreviewed vendor replacement enters the tree without a verifiable source hash. + +#### Impact + +Reduced reproducibility, harder incident response, and increased supply-chain uncertainty. + +#### Recommendation + +Pin production images by digest, automate controlled update PRs, generate an SBOM, record HTMX source/version/checksum, and update the asset after compatibility testing. + +#### Safer Example + +Use `image: mongo:7@sha256:` and store a vendor manifest containing upstream URL, release tag, SHA-256, and license. + +#### Suggested Tests + +Add CI checks rejecting production `latest`/unpinned images and verifying vendored asset checksums and licenses. + +#### References + +CWE-1104; OWASP Top 10 A06:2021; SLSA provenance guidance. + +#### Assumptions / Limitations + +Registry attestations and external deployment pinning were not available for inspection. “Current” upstream version was checked on 2026-08-10. + +### Finding ID: SEC-008 + +#### Title + +Internal datastores rely primarily on network isolation + +#### Severity + +Low + +#### Confidence + +Medium + +#### Affected Files / Components + +`deploy/docker-compose.prod.yml:21-57,78-87`, MongoDB and Qdrant connections. + +#### Description + +Production does not publish datastore ports, which is a strong boundary, but the application connects without datastore credentials and over plaintext HTTP/MongoDB transport within the Compose network. A compromised peer container or host-level network foothold could access or observe the stores directly. + +#### Evidence + +The production URI is `mongodb://mongodb:27017` and Qdrant URL is `http://qdrant:6333`; neither service defines authentication. Ports remain private to the Compose network and the services use `no-new-privileges`. + +#### Attack Scenario + +An attacker compromises the application or another container attached to the same network and directly queries MongoDB/Qdrant, bypassing application authorization and audit logic. + +#### Impact + +Bulk disclosure or modification of workspace data and vectors after an existing network/container compromise. + +#### Recommendation + +Enable service authentication and least-privilege credentials; split networks where practical; evaluate TLS/mTLS for cross-host or higher-assurance deployments; rotate credentials through an external secret manager. + +#### Safer Example + +Create a dedicated MongoDB application user scoped to the Relata database and configure a Qdrant API key via the protected production env file. + +#### Suggested Tests + +Add deployment smoke tests proving anonymous datastore access fails and the app still passes readiness and integration checks with credentials enabled. + +#### References + +CWE-306; CWE-319; OWASP ASVS V9. + +#### Assumptions / Limitations + +The current single-host private network materially lowers likelihood. Exact support and operational costs for datastore TLS/auth must be validated against the deployed versions. + +## 8. Blackhat-Style Abuse Paths + +1. **Historical token leakage to API access:** obtain a pre-fix secret from history/logs, call scoped API routes, then use read results to target higher-value data. Breakpoints are token rotation, short TTLs, scope minimization, hashed-at-rest token storage, and the fixed no-URL creation response. +2. **Member session to capacity exhaustion:** compromise a member account, enqueue allowed uploads, and issue model-backed queries until jobs/model capacity saturate. Existing size/worker bounds limit each operation; workspace/global admission control would break the chain earlier. +3. **Container foothold to datastore bypass:** compromise a network peer, connect directly to unauthenticated stores, and bypass workspace checks. Private networks reduce initial reachability; datastore credentials and network segmentation reduce post-compromise blast radius. + +## 9. Denial-of-Service and Resource Exhaustion Review + +Request bodies, password length, document bytes/pages, result limits, retry counts, worker concurrency, model responses, and login limiter retention are bounded. Negative search paging and attacker-influenced PHC allocation were fixed. Go code contains no obvious user-controlled unbounded goroutine creation. Remaining risk is aggregate authenticated workload across uploads, embeddings, analysis, and jobs (SEC-006). Safe test execution also exposed that concurrent integration suites can exhaust Qdrant file resources; the complete security suite passes sequentially in 508 seconds. + +## 10. Cryptography and Key Management Review + +Passwords use Argon2id at 64 MiB and three iterations with random 16-byte salts; comparisons are constant-time. Sessions and high-entropy API tokens are stored as hashes, and randomness comes from `crypto/rand`. OIDC verifies supported RSA signatures, issuer, audience, expiry, issued-at time, nonce, and minimum RSA key size; redirect following is disabled for discovery/key requests. No custom cipher or predictable secret generator was found. TLS termination and certificate policy live outside this repository and require manual verification. Post-quantum migration is not urgent for password hashing or random bearer tokens; operators should track interoperable hybrid TLS/OIDC support and crypto-agility rather than deploy bespoke algorithms. + +## 11. Secrets Lifecycle and In-Memory Credential Review + +No real secret was found in tracked examples or source. `.env` is ignored and now mode `0600`; production secrets are documented outside the repository. Tokens are displayed once and stored hashed, while OAuth/OIDC and datastore credentials enter via configuration. Go strings cannot be reliably zeroized, so passwords/tokens may persist until garbage collection; no `pprof` or debug dump endpoint was found. Panic redaction was strengthened, but host swap, core dumps, observability exports, and proxy/header redaction need operational verification. Prefer short-lived credentials and a secret manager where feasible. + +## 12. Memory and Resource Safety Review + +The production build disables CGO and no `unsafe`/native FFI surface was identified, substantially reducing classic memory-corruption risk. The pure-Go PDF dependency handles hostile structured input; byte/page caps and generic panic recovery contain failures but do not replace upstream maintenance and fuzzing. Collections, queues, retry loops, and parser/model outputs have local bounds. Aggregate workload remains the principal resource risk. + +## 13. Dependency and Supply-Chain Review + +`go mod verify` passed. `govulncheck -show verbose ./...` found no reachable symbol or package vulnerability; GO-2026-5932 affects an unimported `x/crypto/openpgp` package only. Available non-security updates include several direct/indirect modules and should be applied through reviewed, tested update PRs. Production image digests, SBOM/attestation generation, and vendored HTMX provenance are absent (SEC-007). The Docker build is multi-stage, CGO-disabled, and runs from a minimal non-root image. + +## 14. Authentication and Authorisation Review + +Local login, OAuth/OIDC, sessions, scoped API tokens, role checks, workspace identifiers, and audit events were traced. Login has rate limiting and anti-enumeration behavior; session cookies and CSRF handling are appropriately constrained in code. Repository queries consistently accept a principal/workspace filter in reviewed paths. No horizontal/vertical authorization bypass was confirmed. Production proxy correctness, OAuth provider settings, session revocation operations, and pre-fix token rotation require operator validation. + +## 15. Input Validation and Output Encoding Review + +JSON bodies and uploads are size-limited, identifiers and enums are validated, pagination/results are normalized, SQL is not used, Mongo filters are constructed rather than directly decoded from clients, and HTML templates use contextual escaping. PDF/page work is capped and model outputs are schema-checked with deterministic fallback. The negative search offset defect was fixed. Continue fuzzing parsers and filter normalization, especially after dependency updates. + +## 16. Frontend HTML/JavaScript Robustness Review + +Templates use escaped rendering and CSP/CSRF integration; no application `innerHTML` sink or credential-bearing debug log was identified. The clipboard handler previously allowed rejected promises and weak fallback behavior. It now handles missing sources, unavailable Clipboard API, and rejection while avoiding logging the token or full error object. A real-browser test is still needed for Clipboard API, CSP, HTMX navigation, focus, and accessible status announcements. + +## 17. Infrastructure and Deployment Review + +The app binds to loopback at the host, has a read-only filesystem, drops all capabilities, sets `no-new-privileges`, uses bounded tmpfs and rotated logs, and stores data in named volumes. MongoDB/Qdrant are not published in production. `docker compose ... config --no-env-resolution --quiet` passed. Residual issues are image pinning, datastore defense in depth, lack of visible container CPU/memory/PID limits, backup encryption/retention, and external nginx/systemd/TLS controls that were not inspectable. + +## 18. Logging, Monitoring, and Error Handling Review + +Client errors are stable and avoid internal details; request IDs and audit records support correlation. Panic values are now excluded from HTTP logs, stored job errors, and PDF errors. JSON log rotation is configured. No evidence of alert thresholds for login abuse, queue saturation, invalid stored hashes, datastore auth failures, or token misuse was found; add metrics and alerts without high-cardinality or sensitive labels. + +## 19. Test Coverage and Security Regression Gaps + +New regressions cover URL-secret leakage, reflected secret queries, negative offset normalization, hostile PHC parameters, panic-secret redaction, and clipboard failure syntax. `make check` passed vet, staticcheck, and the race-enabled full unit suite. `make test-security` passed its unit and end-to-end security suites. Gaps remain in browser interaction testing, authenticated load/quotas, datastore-auth deployment testing, backup restore/encryption drills, image/provenance policy, and fuzzing beyond existing seeds. Integration suites share services and should not be run concurrently; stale test collections caused one environmental Qdrant failure before cleanup and a sequential pass. + +## 20. Prioritised Remediation Plan + +- **Immediate:** rotate any token that may have appeared in pre-fix URL logs/history; deploy the five fixed controls; protect and encrypt new backups. +- **Short term:** implement workspace/user admission limits and queue/storage quotas; pin production images; update and checksum HTMX; alert on invalid hashes and saturation. +- **Medium term:** enable MongoDB/Qdrant authentication, assess internal TLS/network segmentation, automate SBOM/vulnerability/provenance checks, and add browser/security load tests. +- **Long term:** perform regular restore drills, external proxy/TLS reviews, tenant-isolation tests, and crypto-agility reviews as interoperable post-quantum standards mature. + +## 21. False Positives / Needs Manual Verification + +- TLS, HSTS, proxy header trust, request limits, and access-log redaction at nginx/systemd were outside the repository. +- `/etc/relata/relata.env` was permission-protected and intentionally not read; its mode/content and secret rotation require operator verification. +- Backup encryption, retention, off-host ACLs, and restore viability were not observable. +- Live OAuth/OIDC provider configuration and redirect registration were not exercised. +- Registry digests/attestations, production runtime resource limits, host firewalling, swap, core-dump, and log-export policies require deployment inspection. +- No advisory was found for vendored HTMX 2.0.4, but provenance and compatibility with 2.0.9 still need validation. + +## 22. Final Notes + +All safe, confirmed code and local-file-permission fixes were implemented and tested. The remaining findings are defense-in-depth or aggregate-abuse concerns, not evidence of an anonymous direct compromise. Reassess after deployment configuration is available and whenever auth, parser/model, tenancy, or infrastructure boundaries change.