first commit
Some checks failed
Validate, publish and deploy / validate (push) Successful in 2m2s
Validate, publish and deploy / publish-and-deploy (push) Failing after 8s

This commit is contained in:
Cauê Faleiros
2026-09-15 16:42:34 -03:00
commit 98c951d374
170 changed files with 95988 additions and 0 deletions

175
SECURITY_REPORT.md Normal file
View File

@@ -0,0 +1,175 @@
# Local security closeout
Date: 2026-09-15
## Scope and conclusion
This report covers the localhost-only Site, Portal/API, Kanban, PostgreSQL,
MinIO, ClamAV, and fake integration worker. It does not approve production use
or real Mercado Pago, R2, Tiny/Olist, WhatsApp, freight, or other providers.
Malware scanning is a quarantine control; it is not artwork or print pre-flight.
The local stack is healthy and its security regressions pass. Existing orders
and the named PostgreSQL/MinIO volumes were preserved. Open dependency and image
findings remain and are recorded below; there is no claim of zero vulnerabilities,
complete OWASP compliance, or production readiness.
## Implemented controls
- Loopback-only published ports, local-only adapter guards, internal API/worker/
database/scanner network, Host checks, cross-origin write rejection, CSP,
frame denial, MIME sniffing protection, and no interactive API documentation.
- Escaped untrusted filenames and browser regression coverage with CSP bypassed.
- Expiring, revocable, hashed HttpOnly operator sessions. No Basic credentials or
operator password are retained in browser storage.
- Seven-day revocable customer sessions, stronger scrypt password hashes, legacy
verification and upgrade, comparable missing-account password work, and login
throttling.
- Upload extension/size/count quotas, storage quotas, private UUID object keys,
exact signed multipart `Content-Length`, completion/ownership checks, and
five-minute signed downloads.
- Files start `pending`. Only `clean` files may be quoted, approved, paid,
downloaded, attached as final files, or moved into queue/printing states.
Unknown, scanner error, unsafe/encrypted, over-limit, and malware outcomes fail
closed. Rejected/error files expire within three days.
- Restricted PostgreSQL and MinIO runtime identities provisioned separately from
administrator credentials. Containers use read-only filesystems/capability
drops where compatible.
- Structured redacted security logs plus a 30-day PostgreSQL event table. Worker
health includes outbox progress, scan-thread liveness, and a live ClamAV PING.
The alert summary also reports signature age.
- Logout revokes server sessions and clears checkout keys and IndexedDB File blobs
across open Site tabs.
- Production delivery definitions use unprivileged application/web users,
read-only filesystems, dropped capabilities, external Swarm secrets, private
service networking, immutable base images, commit-SHA rollback tags,
health-monitored rolling updates, and automatic application rollback. A
fail-closed source/configuration gate prevents the current local-only runtime
from being released as production.
## Verified checks
All results below were observed against the final application source. Smoke and
workflow were repeated after the refreshed PostgreSQL 17 image was activated.
| Check | Result |
|---|---|
| Pricing parity against Site JavaScript | Pass: all 4,444 comparisons plus invalid inputs |
| Security regression | Pass: headers, Host/origin, sessions, quotas, multipart signing, throttling |
| Real ClamAV EICAR regression | Pass: rejected and blocked from download/quote; clean control released |
| Smoke workflow | Pass: multipart, ownership, all modes, pricing/freight, payment idempotency, states/history |
| Customer/final-file workflow | Pass: identity, revocation, corrections, secure downloads, invalidation and queue gate |
| Runtime security | Pass: PostgreSQL/MinIO least privilege, hashes, quarantine and scanner failure behavior |
| Retention | Pass: expired bytes removed, live bytes preserved, metadata retained |
| Browser workflow | Pass: end-to-end flow, filename XSS probe, no stored operator password, logout blob cleanup |
| Dependency lock | Pass: 26 exact packages, SHA-256 hashes on every entry, direct-pin parity, hash-enforced image build, `pip check` |
| Staging readiness gate | Pass with synthetic non-secret metadata in a network-disabled container; unsafe/incomplete regression cases rejected |
| Production delivery definitions | Pass: unit/syntax/YAML checks, Swarm render, immutable-base image builds, non-root read-only web runtime and Host rejection |
| Production source preflight | Expected block: local-only/fake adapters and Docker secret-file loading are not production implementations |
| Production ClamAV runtime | Pass: UID 100:101, read-only filesystem, no capabilities/no-new-privileges, live PONG |
| Repository secret scan | Pass: no HIGH/CRITICAL Trivy secret findings; release workflow enforces the same gate |
## Malware-scanner operations
The scanner image is digest-pinned and has no external network route. It uses
the signatures bundled into that image. On closeout it reported ClamAV
`1.5.4/28122/Sun Sep 13 06:26:25 2026`; the summary calculated 31.8 hours of age,
below the seven-day alert threshold.
The multipart transport supports uploads up to 5 GiB, but `SCAN_MAX_BYTES` and
ClamAV stream limits release at most 128 MiB by default. Larger files remain
blocked. Supporting larger files requires a deliberate resource/timeout design,
not simply increasing the upload limit.
Run:
```bash
docker compose exec -T api python -m local.security_status
```
An exit status of 1 requires review. At closeout, attention was expected because
the regression suite produced two rate-limit alerts, 20 synthetic failed operator
logins, and two rejected `SECURITY-EICAR.cdr` fixtures. Both rejected fixtures
expire on 2026-09-17. ClamAV was available and its signatures were not stale.
Do not automatically dismiss later alerts: verify filename, timestamp, test run,
scanner availability, and signature age. Treat non-test rejected files, scanner
errors, unexplained authentication bursts, or stale signatures as incidents.
## Dependency and image audit
`pip-audit` inspected the exact packages installed in the hash-enforced rebuilt API
and found no known Python advisories on 2026-09-15. All 26 direct and transitive
runtime packages are pinned with artifact hashes in `local/requirements.lock`.
`local/lock_dependencies.sh` regenerates it in a disposable Python 3.12 container.
This is a point-in-time package-database result, not proof that the dependencies
or image are vulnerability-free. Scheduled lock refresh and audit automation remain
unfinished.
Trivy JSON reports are in `output/security/`. HIGH/CRITICAL results after the
available custom-image package upgrades were:
| Image | Findings | Qualification |
|---|---:|---|
| API | 46 HIGH | 44 Debian records had no fix; Trivy's two Python records named `msgpack` and `setuptools`, which `pip list` confirmed are absent from the runtime. Trivy warned that the third-party SBOM may be inaccurate. |
| Site | 5 HIGH | Nginx package records with fixes listed by Trivy, but the current official `nginx:1.28-alpine` image/repository did not supply them. |
| PostgreSQL 17 | 30 HIGH, 1 CRITICAL | Nine Alpine library records and 22 records in `/usr/local/bin/gosu`; presence is confirmed, reachability through this local stack is not. |
| MinIO | 102 HIGH, 6 CRITICAL | Findings span the MinIO and `mc` binaries and two OS packages. A verified local clean-object archive now exists, but the old pinned release was not changed without a tested version-migration and rollback plan. |
| ClamAV | 0 HIGH/CRITICAL | This scan result is not a guarantee that no vulnerability exists. |
| Production API validation image | 55 HIGH, 3 CRITICAL | 44 records had no fix. Fourteen listed fixes, but the `msgpack` and `setuptools` records came from a third-party SBOM and both packages were confirmed absent with `pip list`; the remaining fixed records are Debian packages. |
| Production web validation image | 52 HIGH, 2 CRITICAL | All 54 records listed fixed Alpine versions. A current approved Nginx base digest must replace the locally available validation base before release. |
Scanner presence is evidence, while exploitability/reachability requires separate
analysis. MinIO and the remaining base-image findings block any production-readiness
claim even though ports are loopback-only here. The production validation reports
are `production-api-container-audit.json` and
`production-web-container-audit.json`; both make the release workflow's
HIGH/CRITICAL gate fail. Counts reflect the 2026-09-15 Trivy database and can
change when the advisory database or selected base digest changes.
## Production delivery security boundary
The files in `deploy/` and `.gitea/workflows/` are a guarded delivery mechanism,
not an approval to operate the current application on the public internet. The
single Gitea workflow requires a protected Docker runner, exact commit checkout,
digest-pinned base/scanner images, regressions, and HIGH/CRITICAL Trivy gates.
It publishes both `latest` and the full commit SHA, then calls the Portainer
webhook. Application/provider secrets are created directly as versioned external
Swarm secrets and never cross the workflow. Rollback selects the prior commit SHA
in Portainer and does not roll back the database.
The gate currently identifies real blockers: production adapters and authenticated
payment webhooks are absent, the runtime intentionally rejects production/R2,
Docker secret-file configuration is not implemented, approvals are unset, and
the existing image findings are unresolved. These checks must be satisfied by
implementation and review, not by replacing the checks with permissive values.
## PDF.js review
The Site loads version 3.11.174 from a versioned CDN URL. That version is affected
by [GHSA-wgrm-67xf-hhpq](https://github.com/mozilla/pdf.js/security/advisories/GHSA-wgrm-67xf-hhpq),
whose documented workaround is `isEvalSupported:false`; the existing Site call
already sets that value, so the known eval path is mitigated and is not reported
as unmitigated. The newer
[GHSA-hq66-cqwq-w95j](https://github.com/mozilla/pdf.js/security/advisories/GHSA-hq66-cqwq-w95j)
affects versions from 5.6.83 up to the patched 6.2.108 and therefore does not
include 3.11.174.
Version 3.11.174 is nevertheless old, remotely loaded, and not a satisfactory
long-term dependency posture. Plan a compatibility-tested upgrade and preferably
vendor or integrity-pin the asset. Keep script execution disabled and do not
weaken CSP merely to support a preview.
## Before any staging or production work
- Resolve or formally accept current MinIO, PostgreSQL, Nginx, and Debian image
findings. Use the verified local clean-object bundle to rehearse a MinIO
migration and rollback; it is not a scheduled, offsite, or production backup.
- Schedule controlled dependency-lock refreshes and exact-runtime audits; review
and test every resulting version change.
- Establish a signature update/rebuild process that works without giving the
scanner an unrestricted external network route.
- Replace disposable local secrets; add TLS, production session/cookie settings,
account verification/recovery, centralized monitoring, and complete backup/
restore procedures.
- Re-run every security, malware, workflow, browser, retention, dependency, and
image check in the target staging architecture.