CodeVetter · Repo Unpack · Risk map
strapi/strapi
These are source observations and explicitly labeled hypotheses, not confirmed vulnerabilities. Startup and publication are persistence hotspots because they synchronize schemas or replace related rows. Authentication and MCP rely on different enforcement paths, and upload provider operations cross a storage boundary outside database transactions. Configuration compatibility, global state, and CI conditions require focused review when changing these areas.
- Startup has a broad database blast radius: bootstrap runs schema.sync, conditional orphan-morph repairs, and a one-time join-table repair. The registered discard-drafts migration clones/remaps persisted data, and its down implementation throws 'not implemented'.
- Publishing deletes old published rows before recreating variants and synchronizing multiple relation classes. Correctness depends on retaining repository transaction wrapping; Database.transaction reuses an existing transaction for nested calls and rolls back rejected callbacks.
- auth:false bypasses ordinary authenticate and verify. MCP deliberately uses this route configuration but performs admin-token authentication inside handlePost; edits must preserve that independent boundary and its ability/user propagation.
- Hypothesis: a metadata-write failure after successful provider upload could leave stored bytes without a corresponding media row. The inspected uploadFileAndPersist/add sequence writes provider bytes before database metadata, while upload's finally cleans temporary work rather than showing provider compensation. (inferred)
- Hypothesis: callers passing absolute paths to StrapiFS could escape the intended application root. normalizePath strips leading relative traversal and then calls path.resolve(app.root, normalizedPath), without an explicit containment check in that function; exploitability and caller reachability were not established. (inferred)
- Global instance coupling remains despite guidance preferring injection: createStrapi assigns global.strapi, Document Service repository/common use ambient strapi, and destroy deletes the global and removes all process listeners. This is a source-observed isolation hotspot for multi-instance or lifecycle changes.
- GraphQL warns when depthLimit/maxLimit are unbounded or invalid, but preserves depthLimit as configured rather than imposing a finite fallback. Landing-page configuration can explicitly enable the local playground in production; custom Apollo configuration is merged into defaults.
- The TypeScript CI condition checks global or backend twice and omits frontend, although the frontend filter independently matches admin source changes. This is a source-observed job-selection mismatch; actual skipped runs or downstream defects were not verified.