Skip to main content

security-audit-api-2fa

Checks 2FA enforcement across GraphQL V2 mutations. Use for coverage gaps or on-demand checks.

Datos de origen

Repositorio
opencollective/monorepo
Última actividad en el origen
1 de octubre de 2026 a las 05:48
Idioma detectado de SKILL.md
inglés
Estrellas
3
Forks
3

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
2 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
security-audit-api-2fa
description
Checks 2FA enforcement across GraphQL V2 mutations. Use for coverage gaps or on-demand checks.
# API GraphQL V2 2FA completeness hunter Deterministic completeness check of **two-factor enforcement** on every GraphQL V2 mutation in `opencollective-api`. For engineers running on-demand checks. This hunter **records and classifies**. The enumerator does not decide Bug vs hardening. ## Enumerator From the workspace root: ```bash node .agents/skills/security-audit/scripts/enumerate-2fa-coverage.cjs --root opencollective-api --out /tmp/opencode/v2-2fa.json ``` `--root` defaults to `OC_API_ROOT`, then `./opencollective-api`, then `/workspace/opencollective-api`. Also run `enumerate-v2-mutations.cjs` when you need the raw mutation list. Smoke test (no extra deps): ```bash node --test .agents/skills/security-audit/scripts/enumerators.test.cjs ``` ## Load known-safe patterns Read `.agents/skills/review-feature-security/SKILL.md` when that skill is present. Otherwise use `AGENTS.md` Security: public GraphQL introspection and permissive API CORS are not defects. OWASP framing: Multifactor Authentication. This skill's outputs (classification, optional findings.json, Bug) are the source of truth, not the cheat sheet. ## Classify every mutation For each row in the enumerator JSON, trace `file` + `line` + `twoFactor.callees` (1-2 hops into `server/graphql/common/*`). Assign **one** class: | Class | When | Verdict | | --- | --- | --- | | **public/guest N/A** | Unauthenticated or guest-only (example: `confirmGuestAccount`) | Not a 2FA finding | | **read-only N/A** | No durable write, payout, token, or admin policy change | Not a 2FA finding | | **admin write / REQUIRE_2FA_FOR_ADMINS** | Admin (or host-admin) mutation that changes money, payout methods, vendors, legal docs, hosting, or equivalent. Must follow host policy `REQUIRE_2FA_FOR_ADMINS` via `twoFactorAuthLib.enforceForAccount` or `enforceForAccountsUserIsAdminOf` (which call `validateRequest` when the policy or user 2FA is on) | Missing call with a real threat model is **confirmed** | | **user-has-2FA-enabled** | Path that should prompt when the acting user already has 2FA enrolled (`validateRequest` / `enforceForAccount` without waiting only for host policy) | Missing call is confirmed only with a real threat model | | **intentional onlyAskOnLogin / preAuthorize2FA** | `onlyAskOnLogin: true` or `TWO_FACTOR_SESSIONS_PARAMS` / `preAuthorize2FA` is an explicit product choice (login-time or pre-authorized token) | Hardening at most, not a Bug, unless the option skips a required payout/admin gate | `twoFactor.sessionParams` means the script saw `TWO_FACTOR_SESSIONS_PARAMS` and/or `preAuthorize2FA`. `onlyAskOnLogin` is login-time 2FA, not a fresh prompt for the mutation. ## What is confirmed **Confirmed** = missing 2FA call on an admin-write mutation with a **real threat model**, in the class of `editVendor` payout 2FA bypass ([opencollective-security #200](https://github.com/opencollective/opencollective-security/issues/200)). Unambiguous missing call: confirm from **source trace + threat model**. Mocha PoC when cheap (phase 2). Do not file from enumerator flags alone. **Not a Bug:** defense-in-depth extra prompts after login (for example `onlyAskOnLogin` on tier edits). That is hardening. ## Fingerprint `oc:api:2fa:graphql.v2.mutation.<name>[.<subpath>]` Examples: `oc:api:2fa:graphql.v2.mutation.editVendor`, `oc:api:2fa:graphql.v2.mutation.editVendor.payoutMethod`. Stable across runs. No line numbers, waves, or severity in the fingerprint. ## Dedup and filing 1. Search `opencollective-security/harness/index.json` (when present). 2. Search GitHub `opencollective/opencollective-security` issues (open and closed). 3. Grep `reports/` and `internal/` in the security repo checkout for the same fingerprint. 4. Upsert hunt fields (must not rewrite `reports[]`): ```bash node .agents/skills/security-audit/scripts/patch-index.cjs --mode hunt \ --index opencollective-security/harness/index.json \ --fingerprint 'oc:api:2fa:graphql.v2.mutation.editVendor' \ --verdict confirmed --repo opencollective-api \ --path server/graphql/v2/mutation/VendorMutations.ts --issue 200 ``` 5. File a Bug **only if confirmed and not a duplicate**. Label `source > harness`. ## Artifacts Write under `opencollective-security/harness/api/runs/<YYYY-MM-DD>-<n>/` (and local gitignored `priv/security-audit/` when the security repo is not checked out). Do not patch product code from this hunter. If you produce `findings.json`, validate it: ```bash node .agents/skills/security-audit/validate-findings.cjs path/to/findings.json ``` ## Enumerator limitations Heuristic/regex parser (`lib-scan.cjs`): not TypeScript. Spread fields are not expanded. Runtime field factories are not executed. 2FA hops follow same-file helpers and `server/graphql/common/*` only (not `server/lib/*` except through those hops). If a mutation is missing from JSON, say so; do not invent GraphQL fields. ## Sub-agents Run via sub-agent `security/2fa` (this skill) plus `security/verifier` on every candidate. Hunters must not edit product source.
Ver en GitHub