Pandaward assessment report
acme-shop
asmt_0001_20261028T204903Z · COMPLETE · profile local-passive · revision 5e17870a6457947826be30aa316c027412ea5492 · 2026-10-28T20:49:03Z to 2026-10-28T20:49:03Z
Automated technical security assessment. Not a certification, attestation, legal opinion or independently signed penetration test, and not a guarantee that no vulnerabilities exist. Only the controls listed as PASS were decisively checked, and only for the stated scope, method and point in time.
Summary
Confirmed, open20
Suspected, needs review11
Decisive coverage40%21 of 52 applicable controls
Not decided31controls, never read as secure
Cross-domain edges150 verified · 5 failed · 10 open
Coverage counts decisively tested controls (PASS/FAIL) over applicable controls. It is not a percentage of vulnerabilities found. BLOCKED, UNSUPPORTED, SUSPECTED, INCONCLUSIVE, ERROR and STALE never count as secure.
Confirmed observations (20)
PW-0022 · pull_request_target checks out untrusted PR code
critical CONFIRMED OPEN- Location
.github/workflows/ci.yml:8- Control
- N-003 pull_request_target workflows do not check out untrusted PR code
- CWE
- CWE-829
- Why
- pull_request_target runs with repository secrets and a write token; checking out the PR head lets any fork author run code with them.
- Fix
- Use pull_request for building untrusted code, or split into an unprivileged build and a privileged workflow_run that only consumes artifacts.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-cicd completes and no longer observes it.
- Evidence
ev_4a7f9c2c4be3bcdbvia builtin-cicd
PW-0004 · Hardcoded GitHub token
high CONFIRMED OPEN- Location
app.py:8- Control
- E-001 No high-confidence secret patterns in repository files
- CWE
- CWE-798
- Why
- A value matching the GitHub token format is stored in the repository. The value is masked in all Pandaward output.
- Fix
- Revoke and rotate the credential at the provider first, then remove it from the code and git history; load it from a secret manager or environment at runtime.
- Retest
- Re-run `pandaward scan`; also verify with the provider that the old credential is revoked.
- Evidence
ev_4fc7c8c69e031156via builtin-secrets
PW-0005 · Hardcoded Stripe live secret key
high CONFIRMED OPEN- Location
src/server.js:2- Control
- E-001 No high-confidence secret patterns in repository files
- CWE
- CWE-798
- Why
- A value matching the Stripe live secret key format is stored in the repository. The value is masked in all Pandaward output.
- Fix
- Revoke and rotate the credential at the provider first, then remove it from the code and git history; load it from a secret manager or environment at runtime.
- Retest
- Re-run `pandaward scan`; also verify with the provider that the old credential is revoked.
- Evidence
ev_17b39394ce37dd0avia builtin-secrets
PW-0006 · Credential or environment file tracked in git
high CONFIRMED OPEN- Location
.env- Control
- E-002 Environment and credential files are not tracked in git
- CWE
- CWE-538
- Why
- This file type usually holds credentials and is committed to git. Pandaward did not read its content.
- Fix
- Rotate any credentials it contains, `git rm --cached` it, add it to .gitignore, and purge it from history if the repository is shared.
- Retest
- Re-run `pandaward scan`; the file must no longer be tracked.
- Evidence
ev_2b3c5175a0b4065cvia builtin-secrets
PW-0008 · TLS certificate verification disabled
high CONFIRMED OPEN- Location
app.py:5- Control
- E-003 TLS certificate verification is not disabled in code
- CWE
- CWE-295
- Why
- Certificate verification is turned off, so any network attacker can impersonate the server.
- Fix
- Remove the override; trust a specific CA bundle if a private CA is needed.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_e8d11c07675dc9abvia builtin-code
PW-0009 · Shell command execution
high CONFIRMED OPEN- Location
app.py:6- Control
- D-002 No shell command construction through a shell interpreter
- CWE
- CWE-78
- Why
- Command runs through a shell interpreter.
- Fix
- Use subprocess.run([...], shell=False) with an argument list.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_94913aefcc6346eevia builtin-code
PW-0010 · Dynamic code evaluation
high CONFIRMED OPEN- Location
app.py:7- Control
- D-001 No dynamic code evaluation (eval/new Function/exec of strings)
- CWE
- CWE-95
- Why
- eval/exec evaluates strings as Python code.
- Fix
- Use ast.literal_eval for literals or explicit parsing; never eval input.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_a9c4d034c668acc8via builtin-code
PW-0014 · Dynamic code evaluation
high CONFIRMED OPEN- Location
src/server.js:8- Control
- D-001 No dynamic code evaluation (eval/new Function/exec of strings)
- CWE
- CWE-95
- Why
- Strings are evaluated as code. If any part of the string can be influenced by a user, this is code injection.
- Fix
- Replace eval/new Function with explicit parsing or a lookup table; never evaluate strings.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_7eb1da32ab0560fevia builtin-code
PW-0017 · CORS allows any origin with credentials
high STRONGLY_SUPPORTED OPEN- Location
src/server.js:4- Control
- H-002 CORS is not configured as wildcard together with credentials
- CWE
- CWE-942
- Why
- Any origin (or a reflected origin) is allowed together with credentials, so other sites can make authenticated reads.
- Fix
- Use an explicit allowlist of trusted origins when credentials are enabled.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_8f75c59732ca936dvia builtin-code
PW-0021 · Untrusted event data interpolated into a run script
high CONFIRMED OPEN- Location
.github/workflows/ci.yml:11- Control
- N-002 No untrusted event data interpolated into run: scripts
- CWE
- CWE-78
- Why
- Attacker-controlled text (titles, bodies, branch names) is expanded into the shell script before it runs, allowing command injection in CI.
- Fix
- Pass the value through an environment variable (env: TITLE: ${{ ... }}) and reference "$TITLE" in the script.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-cicd completes and no longer observes it.
- Evidence
ev_d4c0b7d0aaff8778via builtin-cicd
PW-0026 · Public storage or database exposure
high CONFIRMED OPEN- Location
infra/main.tf:1- Control
- J-004 IaC does not expose public storage or world-open admin ports
- CWE
- CWE-284
- Why
- The resource is configured for public access.
- Fix
- Keep storage and databases private; serve public files through a CDN with explicit, read-only policy.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-infra completes and no longer observes it.
- Evidence
ev_4f9bf0d255e934f1via builtin-infra
PW-0027 · Administrative or database port open to the internet
high STRONGLY_SUPPORTED OPEN- Location
infra/main.tf:6- Control
- J-004 IaC does not expose public storage or world-open admin ports
- CWE
- CWE-284
- Why
- A security group/firewall rule allows 0.0.0.0/0 near an SSH, RDP or database port.
- Fix
- Restrict the source to a VPN/bastion range or use a managed access proxy.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-infra completes and no longer observes it.
- Evidence
ev_822dc4e9c892428avia builtin-infra
PW-0029 · Android app is debuggable
high CONFIRMED OPEN- Location
android/app/src/main/AndroidManifest.xml:1- Control
- K-001 Android manifest: not debuggable, no backup, no cleartext traffic
- CWE
- CWE-489
- Why
- Manifest sets android:debuggable="true". Static observation; runtime impact depends on build variant.
- Fix
- Set android:debuggable to false for release builds (use build-type manifest placeholders).
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-mobile completes and no longer observes it.
- Evidence
ev_cdde459f87b81902via builtin-mobile
PW-0020 · GitHub Action not pinned to a commit SHA
medium CONFIRMED OPEN- Location
.github/workflows/ci.yml:9- Control
- N-001 Third-party GitHub Actions pinned to a full commit SHA
- CWE
- CWE-829
- Why
- someone/deploy-action@main uses a mutable reference; whoever controls that tag/branch can change the code that runs with this workflow's secrets.
- Fix
- Pin to the full 40-character commit SHA of a reviewed release and keep the version in a trailing comment; let Dependabot/Renovate update it.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-cicd completes and no longer observes it.
- Evidence
ev_b013c649d18f6fc3via builtin-cicd
PW-0023 · Workflow does not declare GITHUB_TOKEN permissions
medium CONFIRMED OPEN- Location
.github/workflows/ci.yml:1- Control
- N-004 Workflow GITHUB_TOKEN permissions declared explicitly
- CWE
- CWE-250
- Why
- Without a permissions block the token gets the repository default, which may be read-write for everything.
- Fix
- Add `permissions: contents: read` at the top level and grant extra scopes per job only where needed.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-cicd completes and no longer observes it.
- Evidence
ev_bc44fe7969b08ac8via builtin-cicd
PW-0025 · Container runs as root
medium CONFIRMED OPEN- Location
Dockerfile:1- Control
- J-001 Container images do not run as root
- CWE
- CWE-250
- Why
- The final image stage has no non-root USER, so a compromise of the process is root inside the container.
- Fix
- Create an unprivileged user and add `USER <uid>` in the final stage.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-infra completes and no longer observes it.
- Evidence
ev_2dd232b952152e08via builtin-infra
PW-0028 · Package manifest without lockfile
medium CONFIRMED OPEN- Location
package.json:1- Control
- I-001 Every package manifest has a committed lockfile
- CWE
- CWE-829
- Why
- Without a committed lockfile every install can resolve different transitive versions, including a newly published malicious one.
- Fix
- Commit the lockfile and install with the frozen/ci mode (npm ci, pip install --require-hashes, go mod verify).
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-supply completes and no longer observes it.
- Evidence
ev_e081c5b1020366d9via builtin-supply
PW-0019 · GitHub Action not pinned to a commit SHA
low CONFIRMED OPEN- Location
.github/workflows/ci.yml:6- Control
- N-001 Third-party GitHub Actions pinned to a full commit SHA
- CWE
- CWE-829
- Why
- actions/checkout@v4 uses a mutable reference; whoever controls that tag/branch can change the code that runs with this workflow's secrets.
- Fix
- Pin to the full 40-character commit SHA of a reviewed release and keep the version in a trailing comment; let Dependabot/Renovate update it.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-cicd completes and no longer observes it.
- Evidence
ev_4611c27259ceb153via builtin-cicd
PW-0024 · Base image not pinned
low CONFIRMED OPEN- Location
Dockerfile:1- Control
- J-002 Container base images pinned (no latest or missing tag)
- CWE
- CWE-829
- Why
- The base image uses latest or no tag, so builds are not reproducible and can silently pick up a changed image.
- Fix
- Pin a specific version tag, ideally with @sha256 digest, and update it deliberately.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-infra completes and no longer observes it.
- Evidence
ev_98bb7a66c22d7481via builtin-infra
PW-0030 · Android backup enabled
low CONFIRMED OPEN- Location
android/app/src/main/AndroidManifest.xml:1- Control
- K-001 Android manifest: not debuggable, no backup, no cleartext traffic
- CWE
- CWE-530
- Why
- Manifest sets android:allowBackup="true". Static observation; runtime impact depends on build variant.
- Fix
- Set android:allowBackup to false for release builds (use build-type manifest placeholders).
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-mobile completes and no longer observes it.
- Evidence
ev_1c22ef1d4a6f0958via builtin-mobile
Suspected signals (11)
Heuristic or reviewer-proposed hypotheses. They are not confirmed vulnerabilities until verified.
PW-0007 · Unsafe deserialization API
high HYPOTHESIS OPEN- Location
app.py:4- Control
- D-004 No unsafe deserialization APIs on untrusted data
- CWE
- CWE-502
- Why
- Deserializing untrusted data with this API can execute code.
- Fix
- Use JSON or yaml.safe_load; never unpickle data from outside the trust boundary.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_45edd1ca1b90d972via builtin-code
PW-0011 · Model output may reach code or shell execution
high HYPOTHESIS OPEN- Location
app.py:7- Control
- P-001 Model output is not executed as code or shell
- CWE
- CWE-94
- Why
- An execution sink appears on the same line as model output. Prompt injection could turn into code execution.
- Fix
- Treat model output as untrusted data: parse into a typed structure, validate against an allowlist, require human approval for side effects.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_f6f8776e80a54556via builtin-code
PW-0013 · SQL built with string concatenation
high HYPOTHESIS OPEN- Location
src/server.js:6- Control
- D-003 No SQL statements built by string concatenation or interpolation
- CWE
- CWE-89
- Why
- Query text is concatenated with values; if a value is user controlled this is SQL injection.
- Fix
- Use parameterized queries / prepared statements or the ORM query builder.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_9163cd2dde765988via builtin-code
PW-0015 · Shell command built from a string
high HYPOTHESIS OPEN- Location
src/server.js:8- Control
- D-002 No shell command construction through a shell interpreter
- CWE
- CWE-78
- Why
- child_process.exec or shell:true runs the command through a shell; interpolated values allow command injection.
- Fix
- Use execFile/spawn with an argument array and shell:false; validate arguments against an allowlist.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_18bcf670b9fe88b6via builtin-code
PW-0018 · Webhook handler without visible signature verification
high HYPOTHESIS OPEN- Location
src/server.js:7- Control
- G-001 Webhook handlers verify a signature before acting on the payload
- CWE
- CWE-345
- Why
- No signature/HMAC verification was found in the file that defines this webhook route. Verification may live in middleware; confirm manually.
- Fix
- Verify the provider signature over the raw request body with a constant-time compare before parsing or acting; reject replays by timestamp/event ID.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_fdf34989adaac10fvia builtin-code
PW-0001 · Route not declared in the OpenAPI contract
medium HYPOTHESIS OPEN- Location
src/server.js:8- Control
- A-003 Declared API contract (OpenAPI) matches discovered routes
- Why
- GET /admin/run is implemented but not documented; undocumented endpoints often miss contract and authorization tests (shadow API).
- Fix
- Document the endpoint in the OpenAPI contract with its security requirements, or remove it if unused.
- Retest
- Re-run `pandaward scan`; the route must appear in the contract comparison.
- Evidence
ev_efa0768a93861314via builtin-inventory
PW-0002 · Route not declared in the OpenAPI contract
medium HYPOTHESIS OPEN- Location
src/server.js:6- Control
- A-003 Declared API contract (OpenAPI) matches discovered routes
- Why
- GET /api/invoices/:id is implemented but not documented; undocumented endpoints often miss contract and authorization tests (shadow API).
- Fix
- Document the endpoint in the OpenAPI contract with its security requirements, or remove it if unused.
- Retest
- Re-run `pandaward scan`; the route must appear in the contract comparison.
- Evidence
ev_47d3f7f67228fdd6via builtin-inventory
PW-0003 · Route not declared in the OpenAPI contract
medium HYPOTHESIS OPEN- Location
src/server.js:7- Control
- A-003 Declared API contract (OpenAPI) matches discovered routes
- Why
- POST /webhooks/stripe is implemented but not documented; undocumented endpoints often miss contract and authorization tests (shadow API).
- Fix
- Document the endpoint in the OpenAPI contract with its security requirements, or remove it if unused.
- Retest
- Re-run `pandaward scan`; the route must appear in the contract comparison.
- Evidence
ev_2de440fb1038ae7evia builtin-inventory
PW-0012 · jwt.decode used (no signature check)
medium HYPOTHESIS OPEN- Location
src/server.js:5- Control
- B-001 JWT verification is not disabled and does not accept the 'none' algorithm
- CWE
- CWE-347
- Why
- jsonwebtoken's decode() does not verify the signature; trusting its output for authorization is unsafe.
- Fix
- Use jwt.verify(token, key, { algorithms: [...] }) for anything security relevant.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_ba4887d7098ce9c5via builtin-code
PW-0016 · Raw HTML sink
medium HYPOTHESIS OPEN- Location
src/server.js:9- Control
- H-001 No raw HTML injection sinks (innerHTML, dangerouslySetInnerHTML, v-html, |safe)
- CWE
- CWE-79
- Why
- Content is inserted as raw HTML. If it can contain user data this is cross-site scripting.
- Fix
- Render as text, or sanitize with a maintained sanitizer (DOMPurify) right at the sink.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-code completes and no longer observes it.
- Evidence
ev_3492a3599d7b8d70via builtin-code
PW-0031 · Exported Android component without permission
medium HYPOTHESIS OPEN- Location
android/app/src/main/AndroidManifest.xml:3- Control
- K-002 Android exported components protected by permission
- CWE
- CWE-926
- Why
- Any installed app can invoke this receiver. Confirm it validates callers and input.
- Fix
- Set android:exported="false" unless required, or protect it with a signature-level permission.
- Retest
- Apply the fix, then run `pandaward retest`; the finding becomes REMEDIATED only when builtin-mobile completes and no longer observes it.
- Evidence
ev_385c21dd4cc2e520via builtin-mobile
Coverage by domain
| Domain | PASS | FAIL | SUSPECTED | BLOCKED | UNSUPPORTED | INCONCLUSIVE | ERROR | STALE | NOT_APPLICABLE |
|---|---|---|---|---|---|---|---|---|---|
| A Asset inventory, architecture and threat model | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
| B Authentication, sessions and identity | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| C Authorization, roles and tenant isolation | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 |
| D Input, output, injection and data flow | 0 | 2 | 2 | 2 | 0 | 0 | 0 | 0 | 0 |
| E Secrets, cryptography, privacy and storage | 1 | 3 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| F Business logic, integrity and financial workflows | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
| G API contracts, integrations and messaging | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
| H Web frontend, browser and client-side controls | 0 | 0 | 2 | 1 | 0 | 0 | 0 | 0 | 0 |
| I Dependencies, SBOM and software supply chain | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
| J Cloud, infrastructure, network and IaC | 0 | 3 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
| K Android application security | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
| L iOS application security | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
| M Dynamic application/API security testing | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| N CI/CD, source control and release security | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| O Observability, detection and recovery | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| P AI/LLM, agents, prompts and MCP | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
| Q Availability, concurrency and abuse resistance | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
| R Reporting, governance and remediation assurance | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Cross-domain edges
| Edge | Scenario | Status | Reason | Provenance |
|---|---|---|---|---|
| AB1 Discovered login endpoints -> session tests | New auth route missing token/session coverage | BLOCKED | not decided: A-002=INCONCLUSIVE, B-003=UNSUPPORTED, B-004=BLOCKED | route:POST:/api/login@src/server.js |
| AC1 Asset owners -> access policies | Orphan routes lack authorization checks | BLOCKED | not decided: C-002=BLOCKED, C-003=BLOCKED | route:POST:/api/login@src/server.js, route:GET:/api/invoices/:id@src/server.js, route:POST:/webhooks/stripe@src/server.js, route:GET:/admin/run@src/server.js |
| AD1 Input entrypoints -> sinks | Ingress path crosses a parsing or command boundary | FAIL | failed controls: D-001, D-002 | control:D-001, control:D-002, control:D-003, control:D-004, file:src/server.js |
| AE1 Asset classification -> secret scan | Secret material flows into config, workflow or IaC | FAIL | failed controls: E-001, E-002 | control:E-001, control:E-002 |
| AG1 Service inventory -> API coverage | Undocumented endpoints bypass contract tests | BLOCKED | not decided: G-002=UNSUPPORTED | openapi.yaml, route:POST:/api/login@src/server.js, route:GET:/api/invoices/:id@src/server.js, route:POST:/webhooks/stripe@src/server.js, route:GET:/admin/run@src/server.js |
| AJ1 Cloud-deployed asset -> exposure | Private API exposed by ingress or policy drift | FAIL | failed controls: J-001, J-004 | route:POST:/api/login@src/server.js, route:GET:/api/invoices/:id@src/server.js, route:POST:/webhooks/stripe@src/server.js, route:GET:/admin/run@src/server.js, Dockerfile, infra/main.tf |
| BC1 Authenticated identity -> authorization | Valid user can access another tenant's object | BLOCKED | not decided: C-001=BLOCKED | route:POST:/api/login@src/server.js, route:GET:/api/invoices/:id@src/server.js |
| BK1 Mobile identity -> Android storage | Token copied to Android insecure storage | FAIL | failed controls: K-001 | android/app/src/main/AndroidManifest.xml, src/server.js, route:POST:/api/login@src/server.js |
| CG1 Object access -> API response | Mass assignment or property-level data access | BLOCKED | not decided: C-001=BLOCKED, G-002=UNSUPPORTED | route:GET:/api/invoices/:id@src/server.js |
| DG1 Webhook input -> API trust | Unsigned callback payload drives privileged state | SUSPECTED | suspected: G-001 | route:POST:/webhooks/stripe@src/server.js |
| DH1 HTML output -> browser | Unescaped backend content reaches the DOM | SUSPECTED | suspected: H-001 | control:H-001 |
| DP1 Prompt content -> tools | Untrusted retrieved text triggers a tool action | BLOCKED | not decided: P-003=UNSUPPORTED | app.py |
| FG1 Payment state -> webhooks | Replay moves payment into an invalid terminal state | BLOCKED | not decided: F-001=BLOCKED | src/server.js, route:POST:/webhooks/stripe@src/server.js |
| FQ1 State machine -> race | Concurrent requests bypass idempotency | BLOCKED | not decided: F-002=UNSUPPORTED, Q-002=UNSUPPORTED | src/server.js |
| IN1 Action dependency -> CI integrity | Unpinned third-party action may change code | FAIL | failed controls: N-001 | .github/workflows/ci.yml |
Control ledger
| Control | Title | Method | Status | Reason |
|---|---|---|---|---|
| A-001 | Repository inventory walk completed without unreadable or skipped files | static | PASS | 9 text files analyzed, none skipped |
| A-002 | Externally reachable routes enumerated with file references | static | INCONCLUSIVE | 4 HTTP routes, 0 GraphQL operations, 0 gRPC methods, 0 queue consumers and 0 cron jobs extracted heuristically with file and line (`pandaward routes`); completeness is not proven without a contract or runtime crawl |
| A-003 | Declared API contract (OpenAPI) matches discovered routes | static | SUSPECTED | 3 heuristic signal(s) need review; not confirmed |
| A-004 | Asset owners, trust boundaries and abuse cases reviewed | manual | BLOCKED | manual-assisted review required (/pandaward:review); not decided by automation |
| B-001 | JWT verification is not disabled and does not accept the 'none' algorithm | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| B-002 | Session cookies are not explicitly configured without Secure/HttpOnly | static | PASS | check completed with no signal (code heuristics); PASS applies to this check only |
| B-003 | Login, reset and MFA state machine tested with negative cases | runtime | UNSUPPORTED | runtime adapter for profile staging-active is not implemented in this release; use manual-assisted review |
| B-004 | Session expiry and revocation enforced server-side | runtime | BLOCKED | needs an identity with revoked: true and authorization_checks in an approved scope manifest, then `pandaward test --profile staging-active` |
| C-001 | Object-level authorization enforced on parameterized routes (BOLA) | runtime | BLOCKED | needs identities and authorization_checks in an approved scope manifest, then `pandaward test --profile staging-active` |
| C-002 | Function-level authorization enforced on privileged routes | runtime | BLOCKED | needs identities and authorization_checks in an approved scope manifest, then `pandaward test --profile staging-active` |
| C-003 | Authorization checks reviewed for every route handler | manual | BLOCKED | manual-assisted review required (/pandaward:review); not decided by automation |
| D-001 | No dynamic code evaluation (eval/new Function/exec of strings) | static | FAIL | 2 confirmed observation(s) |
| D-002 | No shell command construction through a shell interpreter | static | FAIL | 1 confirmed observation(s), 1 suspected |
| D-003 | No SQL statements built by string concatenation or interpolation | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| D-004 | No unsafe deserialization APIs on untrusted data | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| D-005 | Injection probes executed against approved target | runtime | BLOCKED | needs zap.active_scan: true in an approved scope manifest, ZAP installed and `pandaward test --profile staging-active` |
| D-006 | Semgrep data-flow rules (SSRF, path traversal, template injection) and project rules report no findings | external | BLOCKED | semgrep is not installed (optional; run `pandaward doctor`) |
| E-001 | No high-confidence secret patterns in repository files | static | FAIL | 2 confirmed observation(s) |
| E-002 | Environment and credential files are not tracked in git | static | FAIL | 1 confirmed observation(s) |
| E-003 | TLS certificate verification is not disabled in code | static | FAIL | 1 confirmed observation(s) |
| E-004 | No weak hash or non-cryptographic random used for security values | static | PASS | check completed with no signal (code heuristics); PASS applies to this check only |
| E-005 | Gitleaks reports no secrets | external | BLOCKED | gitleaks is not installed (optional; run `pandaward doctor`) |
| F-001 | Business invariants for money and entitlement flows documented and reviewed | manual | BLOCKED | manual-assisted review required (/pandaward:review); not decided by automation |
| F-002 | Idempotency and double-processing tested with synthetic fixtures | runtime | UNSUPPORTED | runtime adapter for profile staging-active is not implemented in this release; use manual-assisted review |
| G-001 | Webhook handlers verify a signature before acting on the payload | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| G-002 | Runtime API authorization matches the declared contract | runtime | UNSUPPORTED | runtime adapter for profile staging-active is not implemented in this release; use manual-assisted review |
| H-001 | No raw HTML injection sinks (innerHTML, dangerouslySetInnerHTML, v-html, |safe) | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| H-002 | CORS is not configured as wildcard together with credentials | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| H-003 | Security response headers present on approved deployed target | runtime | BLOCKED | needs `pandaward test --profile production-observe` with an approved scope manifest |
| I-001 | Every package manifest has a committed lockfile | static | FAIL | 1 confirmed observation(s) |
| I-002 | Dependencies with install-time scripts are listed for review | static | PASS | check completed with no signal (lockfiles, install scripts, requirement pins, MCP configs); PASS applies to this check only |
| I-003 | No known-vulnerable dependencies in an advisory database | external | BLOCKED | osv-scanner is not installed (optional; run `pandaward doctor`) |
| I-004 | Python requirements pinned to exact versions | static | NOT_APPLICABLE | auto: no 'python_reqs' assets found in inventory (review this decision) |
| J-001 | Container images do not run as root | static | FAIL | 1 confirmed observation(s) |
| J-002 | Container base images pinned (no latest or missing tag) | static | FAIL | 1 confirmed observation(s) |
| J-003 | No privileged containers or host networking in compose/Kubernetes | static | NOT_APPLICABLE | auto: no 'orchestration' assets found in inventory (review this decision) |
| J-004 | IaC does not expose public storage or world-open admin ports | static | FAIL | 1 confirmed observation(s), 1 suspected |
| J-005 | Trivy reports no IaC misconfigurations | external | BLOCKED | trivy is not installed (optional; run `pandaward doctor`) |
| K-001 | Android manifest: not debuggable, no backup, no cleartext traffic | static | FAIL | 2 confirmed observation(s) |
| K-002 | Android exported components protected by permission | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| K-003 | Android runtime storage and transport verified on emulator | runtime | BLOCKED | needs runtime.android_package, a running emulator with the debuggable test build, and `pandaward test --profile local-runtime` |
| K-004 | Android app does not keep credentials in plain SharedPreferences or world-accessible storage | static | PASS | check completed with no signal (android manifest, iOS plist and entitlements, mobile storage checks); PASS applies to this check only |
| K-005 | Built APK manifest: not debuggable, no backup or cleartext, no unprotected exported components | external | NOT_APPLICABLE | auto: no 'apk' assets found in inventory (review this decision) |
| L-001 | iOS App Transport Security does not allow arbitrary loads | static | NOT_APPLICABLE | auto: no 'ios' assets found in inventory (review this decision) |
| L-002 | iOS keychain and storage verified on simulator | runtime | NOT_APPLICABLE | auto: no 'ios' assets found in inventory (review this decision) |
| L-003 | iOS entitlements do not allow debugging outside debug builds | static | NOT_APPLICABLE | auto: no 'ios' assets found in inventory (review this decision) |
| L-004 | iOS credentials kept in the Keychain with a restrictive accessibility class, not in UserDefaults | static | NOT_APPLICABLE | auto: no 'ios' assets found in inventory (review this decision) |
| M-001 | Passive DAST (ZAP baseline) against approved target | runtime | BLOCKED | needs `pandaward test --profile staging-active` with an approved scope manifest and ZAP installed |
| N-001 | Third-party GitHub Actions pinned to a full commit SHA | static | FAIL | 2 confirmed observation(s) |
| N-002 | No untrusted event data interpolated into run: scripts | static | FAIL | 1 confirmed observation(s) |
| N-003 | pull_request_target workflows do not check out untrusted PR code | static | FAIL | 1 confirmed observation(s) |
| N-004 | Workflow GITHUB_TOKEN permissions declared explicitly | static | FAIL | 1 confirmed observation(s) |
| O-001 | Security events logged and alerted (privilege changes, auth failures) | manual | BLOCKED | manual-assisted review required (/pandaward:review); not decided by automation |
| O-002 | Secrets and credentials not written to logs | static | PASS | check completed with no signal (code heuristics); PASS applies to this check only |
| P-001 | Model output is not executed as code or shell | static | SUSPECTED | 1 heuristic signal(s) need review; not confirmed |
| P-002 | MCP server configs pinned and free of inline credentials | static | NOT_APPLICABLE | auto: no 'mcp_config' assets found in inventory (review this decision) |
| P-003 | Prompt-injection and tool-authorization cases tested | runtime | UNSUPPORTED | runtime adapter for profile staging-active is not implemented in this release; use manual-assisted review |
| Q-001 | Rate limiting applied to authentication and expensive routes | manual | BLOCKED | manual-assisted review required (/pandaward:review); not decided by automation |
| Q-002 | Concurrency and duplicate-action tests on stateful flows | runtime | UNSUPPORTED | runtime adapter for profile staging-active is not implemented in this release; use manual-assisted review |
| R-001 | All evidence artifacts of this assessment verify against recorded SHA-256 | static | PASS | 31 evidence artifacts verified against SHA-256 |
| R-002 | Imported third-party analyzer results (SARIF) report no findings | external | NOT_APPLICABLE | auto: no 'sarif' assets found in inventory (review this decision) |
Tool runs
| Adapter | Version | Result | Signals | Detail |
|---|---|---|---|---|
| builtin-cicd | 0.2.1 | OK | 5 | 1 workflows |
| builtin-code | 0.2.1 | OK | 12 | code heuristics |
| builtin-infra | 0.2.1 | OK | 4 | dockerfile/compose/k8s/terraform checks |
| builtin-inventory | 0.2.1 | OK | 3 | 15 assets |
| builtin-mobile | 0.2.1 | OK | 3 | android manifest, iOS plist and entitlements, mobile storage checks |
| builtin-secrets | 0.2.1 | OK | 3 | 16 secret formats checked; 1 sensitive file names recorded without reading |
| builtin-supply | 0.2.1 | OK | 1 | lockfiles, install scripts, requirement pins, MCP configs |
| gitleaks | BLOCKED | 0 | gitleaks is not installed (optional; run `pandaward doctor`) | |
| osv-scanner | BLOCKED | 0 | osv-scanner is not installed (optional; run `pandaward doctor`) | |
| semgrep | BLOCKED | 0 | semgrep is not installed (optional; run `pandaward doctor`) | |
| trivy | BLOCKED | 0 | trivy is not installed (optional; run `pandaward doctor`) |
Evidence index
31 redacted artifacts under .pandaward/private/evidence/, named by SHA-256.
| Evidence | SHA-256 | Collector | Source |
|---|---|---|---|
| ev_17b39394ce37dd0a | 17b39394ce37dd0a0de700dbb903572efdc354be838155d54c2c8d0e2efeb0b8 | builtin-secrets | src/server.js#L2-L2 |
| ev_18bcf670b9fe88b6 | 18bcf670b9fe88b64d139efde10e65e0274fd3ea4a73c2a93e2c4a572da8695c | builtin-code | src/server.js#L8-L8 |
| ev_1c22ef1d4a6f0958 | 1c22ef1d4a6f09581363dd3d521b89f576fca9e2b7bb6e7726d2f7f3b454df37 | builtin-mobile | android/app/src/main/AndroidManifest.xml#L1-L1 |
| ev_2b3c5175a0b4065c | 2b3c5175a0b4065c3599ce12d8dba7960e6c5b9bd6c16c3947e367598bbbd094 | builtin-secrets | .env |
| ev_2dd232b952152e08 | 2dd232b952152e08f1ef75802cc28bd5c6a074299101c0cb03b2cf1b68185a6a | builtin-infra | Dockerfile#L1-L1 |
| ev_2de440fb1038ae7e | 2de440fb1038ae7e66d537bbf6b430507479cf5d1ce6519a58c423374907823d | builtin-inventory | src/server.js#L7-L7 |
| ev_3492a3599d7b8d70 | 3492a3599d7b8d7016a07bcb9ed0773f888387f2c95f9d77d8e6ca53c4012d5d | builtin-code | src/server.js#L9-L9 |
| ev_385c21dd4cc2e520 | 385c21dd4cc2e520f0876003cd58591eaffa08d917771aca8bace033edbe4a72 | builtin-mobile | android/app/src/main/AndroidManifest.xml#L3-L3 |
| ev_45edd1ca1b90d972 | 45edd1ca1b90d972b8b85cde1a248bcffb06f92e712dda6b36da2a3d7fc9fce5 | builtin-code | app.py#L4-L4 |
| ev_4611c27259ceb153 | 4611c27259ceb1535e0118b38d6fcd0380e333979e1415875926554f10ca9f10 | builtin-cicd | .github/workflows/ci.yml#L6-L6 |
| ev_47d3f7f67228fdd6 | 47d3f7f67228fdd6afc263d85982473a7b4838a60bf30fa2fdbc3b75bf60a86e | builtin-inventory | src/server.js#L6-L6 |
| ev_4a7f9c2c4be3bcdb | 4a7f9c2c4be3bcdb8687f118ec4015e3782a9ea4a7080672b281f92d07d6fa0a | builtin-cicd | .github/workflows/ci.yml#L8-L8 |
| ev_4f9bf0d255e934f1 | 4f9bf0d255e934f197e52ca274cb292eb831a90bd499a2021158cc82d14881ac | builtin-infra | infra/main.tf#L1-L1 |
| ev_4fc7c8c69e031156 | 4fc7c8c69e031156263780edf79b4f52804e1991029f5388c4d6ab98516afcaa | builtin-secrets | app.py#L8-L8 |
| ev_7eb1da32ab0560fe | 7eb1da32ab0560fe2ee8962ada80f96dbe720e4c9aeedcadfd3dd40feef13daa | builtin-code | src/server.js#L8-L8 |
| ev_822dc4e9c892428a | 822dc4e9c892428aea1fa57990ff08b0f58ac5f189179141e81ae2d071516875 | builtin-infra | infra/main.tf#L6-L6 |
| ev_8f75c59732ca936d | 8f75c59732ca936db9fb6715c44a20e9772c50aceb3f8d022c970a5700bce04d | builtin-code | src/server.js#L4-L4 |
| ev_9163cd2dde765988 | 9163cd2dde7659880af78bc17e9b265ce83f9248557f2a54824be4725b7647a3 | builtin-code | src/server.js#L6-L6 |
| ev_94913aefcc6346ee | 94913aefcc6346ee4a0057bf92ee3bdaa7889ff39d20b3818bf17f30e656a4b7 | builtin-code | app.py#L6-L6 |
| ev_98bb7a66c22d7481 | 98bb7a66c22d7481eea003e7ec8b2dbabedd051499b73798d6e0f57e013ff363 | builtin-infra | Dockerfile#L1-L1 |
| ev_a9c4d034c668acc8 | a9c4d034c668acc81cd7cdb434c4597d35e6d7568a4840db216326a061460f3f | builtin-code | app.py#L7-L7 |
| ev_b013c649d18f6fc3 | b013c649d18f6fc37f8cefa1ea850deb9289169e1cfec887694e8ca51d5acbe1 | builtin-cicd | .github/workflows/ci.yml#L9-L9 |
| ev_ba4887d7098ce9c5 | ba4887d7098ce9c5f0d133ba772bbe0cf45b1ff2b3d2476df689e3571594bee8 | builtin-code | src/server.js#L5-L5 |
| ev_bc44fe7969b08ac8 | bc44fe7969b08ac86db054aafb4d26b89586d08b0546ef694b8cc58f309a1ff7 | builtin-cicd | .github/workflows/ci.yml#L1-L1 |
| ev_cdde459f87b81902 | cdde459f87b819027a96c9f7a2836db82d3d87d999df46fa3fe668c4097e3dfc | builtin-mobile | android/app/src/main/AndroidManifest.xml#L1-L1 |
| ev_d4c0b7d0aaff8778 | d4c0b7d0aaff8778b011b8b9a3db6440e2d144f22060290a326be3462e364fda | builtin-cicd | .github/workflows/ci.yml#L11-L11 |
| ev_e081c5b1020366d9 | e081c5b1020366d9d14573e4fecfa24b1afacb3bc3f9b5a6472f6245d090d880 | builtin-supply | package.json#L1-L1 |
| ev_e8d11c07675dc9ab | e8d11c07675dc9abaa9d111a717bdc9914443d8969b9f52ab584a747cec0060c | builtin-code | app.py#L5-L5 |
| ev_efa0768a93861314 | efa0768a9386131425422ebad65848b31fefd3a4d9265fab15f93834bc2f61cc | builtin-inventory | src/server.js#L8-L8 |
| ev_f6f8776e80a54556 | f6f8776e80a545566da22965fa764a799f2401818a4b866cc32f2e26914b2a4a | builtin-code | app.py#L7-L7 |
| ev_fdf34989adaac10f | fdf34989adaac10f800ab39fe8ed55cf4515004df04443de3800ab24a195cf02 | builtin-code | src/server.js#L7-L7 |
Generated 2026-10-28T20:49:03Z by pandaward 0.2.1.