{
  "schema": "aaes/capability-pack/1",
  "provider": "snyk",
  "version": "1.0.0",
  "description": "Snyk: read projects, issues and suppression records; update project settings; suppress or reveal findings; and delete monitored projects.",
  "notes": "The endpoint host 'snyk-api.invalid' is a reserved non-production placeholder (an RFC 2606 reserved TLD): substitute the regional base URL for the customer's Snyk tenant before enabling — Snyk documents api.snyk.io/rest, api.us.snyk.io/rest, api.eu.snyk.io/rest and api.au.snyk.io/rest per region, and the API is HTTPS-only. Substitute in every endpoint, in the resource locator and in every egress allowlist entry; the allowlist matches exactly, so all three move together, and substitution is a required deployment step. ORG_ID, PROJECT_ID and ISSUE_ID in the endpoint paths are placeholders to bind to concrete ids before enabling.\n\nThis pack mixes two documented surfaces, project management and project listing register the versioned REST API (JSON:API; every REST endpoint below pins the ?version=2024-10-15 query parameter in the registered endpoint, per Snyk's versioning guidance that integrations send a dated version), while ignore management and issue aggregation register the v1 API, which Snyk's own reference states will eventually be deprecated in favor of the REST API — re-review on pack version bump as those operations move.\n\nApproval classification: collection reads and the POST-with-query-body issue aggregation (a read-only POST whose body carries filters and includeDescription/includeIntroducedThrough flags — it mutates nothing) sit at the minimum R0 tier. Project update is a JSON:API PATCH registered as update at the minimum R2 tier; Consequential effects: the PATCH body can also alter tags, business criticality, environment, lifecycle and test frequency, and this registration does not restrict which attributes a caller changes — test-frequency or criticality changes alter security cadence and reporting, so policy should scope the capability.\n\nCreating an issue ignore is registered as create at the minimum R2 tier because the ignore can be removed again — but an ignore SUPPRESSES a vulnerability or license finding from reporting, and a permanent ignore (no expires attribute) suppresses it indefinitely: the minimum R2 tier is a minimum and policy should require a person and scope this to named actors. Removing an ignore is an HTTP DELETE registered at the minimum R3 tier under the action minimum; its effect is re-exposure of the finding, not suppression.\n\nProject deletion sits at the minimum R3 tier: delete is one of the designated actions requiring human approval and removes the project and its scan history from Snyk.\n\nDocumented exclusions: this pack does not register organization deletion (DELETE /v1/org/{orgId}), member and role management and user provisioning/invitation (access-granting operations needing their own review), importing new targets from source control (POST /v1/org/{orgId}/integrations/.../import — reaches into the connected repository), moving a project to another organization, webhook CRUD, service account administration, and Snyk's reporting/groups endpoints. Source note: the Snyk authentication page was retrieved during the documented review and establishes the 'token <API token>' Authorization scheme for direct API calls (the 'bearer' scheme belongs to Snyk Apps OAuth tokens); the registered REST operations were verified against the fetched projects reference, whose request examples render the pinned dated version parameter.",
  "credential": {
    "secret_ref_id": "secret-ref-snyk-service-account-token",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "A Snyk service account API token, held in the client's own secret manager. Token issuance is external: an administrator creates a service account for the org (or group) in Snyk's settings and stores the API token under this reference; personal user API tokens also work but bind the integration to an individual's account and permissions — prefer a service account. The stored material must be the complete Authorization header value: the scheme 'token', one separating space, then the API token — 'token <API token>'.\n\nPer the retrieved Snyk authentication page, direct API calls authenticate with an 'Authorization: token <API_TOKEN>' header (the 'bearer' scheme is for Snyk Apps OAuth access tokens, not this credential); the REST reference's placeholder 'Authorization: YOUR_API_KEY' example is not the scheme. Expiry and revocation behavior, Snyk API tokens do not carry a caller-chosen TTL — a token remains valid until it is rotated or the owning service account is deleted/disabled, and rotating a token invalidates the previous value; there is no session expiry to rely on, so rotation cadence is the custody job's responsibility and a leaked value must be rotated explicitly.\n\nNote the gap: changing the service account's role narrows FUTURE authorization decisions but does not invalidate the token value itself.\n\nLeast privilege: give the service account an org role with only the permissions the enabled capabilities need (View Organization, View Project, View Project Ignores, plus — according to the reviewed ignores-v1 reference, which lists required permissions per operation — 'Create new project ignores' only if ignore creation is enabled and 'Remove Project Ignores' only if ignore removal is enabled; 'Edit Project Ignores' covers the PUT modify operation this pack does not register); for project deletion, grant the narrowest documented project-delete permission rather than blanket Organization Admin — the retrieved REST projects reference rendered the DELETE operation but no required-permissions list for it during the documented review, so the exact minimum role for deletion must be confirmed against Snyk's permission documentation before the delete capability is enabled — and never a group-admin token.\n\nSnyk rate-limits to 1620 requests per minute per API key; an over-limit call returns 429 and is retried later, not retried in a tight loop.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "snyk.projects.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/rest/orgs/ORG_ID/projects?version=2024-10-15",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "snyk-org",
      "description": "List the projects in one Snyk organization via the versioned REST API — a collection read of project names, origins, types and issue counts, cursor-paginated per Snyk's REST pagination. The ?version=2024-10-15 query parameter is part of the registered endpoint: Snyk versions each REST endpoint by date and recommends pinning one. ORG_ID is a placeholder to bind before enabling; the host is a reserved placeholder to substitute with the tenant's regional base URL.",
      "requires_review": true
    },
    {
      "capability_id": "snyk.project.issues.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/v1/org/ORG_ID/project/PROJECT_ID/aggregated-issues",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "snyk-org",
      "description": "Aggregate a project's issues (vulnerabilities and license issues) via the v1 API. This is a POST-with-query-body endpoint used read-only: the request body carries filters and the includeDescription/includeIntroducedThrough flags, and the operation mutates nothing, so it registers as read at the minimum R0 tier. Responses include severity, CVE/CWE identifiers, exploit maturity and ignore status — security posture data classified as internal data. ORG_ID and PROJECT_ID are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "snyk.ignores.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/v1/org/ORG_ID/project/PROJECT_ID/ignores",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "snyk-org",
      "description": "List the ignores on one project — a collection read of which findings are suppressed, with reason and expiry, and of BY WHOM each ignore was set: the returned creator identifiers are personal data, so the capability is classified as pii (personal data). Snyk's reference notes that ignores from.snyk policy files and from org policies are NOT included in this listing, so this read is not a complete suppression audit on its own. ORG_ID and PROJECT_ID are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "snyk.ignore.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/v1/org/ORG_ID/project/PROJECT_ID/ignore/ISSUE_ID",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create"
      ],
      "resource_id": "snyk-org",
      "description": "Suppress a vulnerability or license issue by creating an ignore. The body accepts ignorePath, reason, reasonType, disregardIfFixable, and optional expires. Without expires, suppression is permanent; the registration does not restrict the body.\n\nThe ignore can later be removed, so create is registered at R2. Suppression removes a finding from reporting and gate review while it is active. Require a person to review the operation and limit policy to named actors and projects.\n\nBind ORG_ID, PROJECT_ID, and ISSUE_ID before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "snyk.ignore.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/v1/org/ORG_ID/project/PROJECT_ID/ignore/ISSUE_ID",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "snyk-org",
      "description": "Remove an ignore and make its suppressed security finding visible again. This deletes the ignore record; restoring suppression requires creating a new record.\n\nRegistered as delete at R3, even though exposing a finding is generally the safer security outcome. AAES approval classification is separate from whether the provider offers a later way to restore suppression. Policy cannot lower the minimum tier.\n\nBind ORG_ID, PROJECT_ID, and ISSUE_ID before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "snyk.project.update",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/rest/orgs/ORG_ID/projects/PROJECT_ID?version=2024-10-15",
      "method": "PATCH",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "update"
      ],
      "resource_id": "snyk-org",
      "description": "Update a project via the versioned REST API (JSON:API PATCH, Content-Type application/vnd.api+json): tags, business criticality, environment, lifecycle, owner and test frequency. Registered as update at the minimum R2 tier.\n\nRequest limits: this registration does not restrict which attributes the PATCH document changes — lowering test frequency or criticality alters the project's security cadence and reporting, so policy should scope the capability and require review for cadence changes. ORG_ID and PROJECT_ID are placeholders; the pinned ?version=2024-10-15 is part of the registered endpoint.",
      "requires_review": true
    },
    {
      "capability_id": "snyk.project.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "snyk-api.invalid"
      ],
      "endpoint": "https://snyk-api.invalid/rest/orgs/ORG_ID/projects/PROJECT_ID?version=2024-10-15",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-snyk-service-account-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "snyk-org",
      "description": "Delete a project from the Snyk organization via the versioned REST API, removing the monitored project and its issue history from Snyk (the underlying repository is untouched; re-importing creates a NEW project, not a restoration). Registered as delete at the minimum R3 tier: delete is one of the designated actions requiring human approval.\n\nOn supported AAES-mediated execution paths, irreversible actions require approval by an authorized person; this does not prevent calls through bypass or observation-only paths. ORG_ID and PROJECT_ID are placeholders; the pinned ?version=2024-10-15 is part of the registered endpoint.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "snyk-org",
      "kind": "api",
      "locator": "https://snyk-api.invalid/rest/orgs/ORG_ID",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-09-22",
    "sources": [
      "https://docs.snyk.io/snyk-api/rest-api/about-the-rest-api (retrieved 2026-09-21)",
      "https://docs.snyk.io/snyk-api/reference/projects (retrieved 2026-09-21)",
      "https://docs.snyk.io/snyk-api/reference/projects-v1 (retrieved 2026-09-21)",
      "https://docs.snyk.io/snyk-api/reference/ignores-v1 (retrieved 2026-09-21)",
      "https://docs.snyk.io/snyk-api/rest-api/authentication-for-api (retrieved 2026-09-21)"
    ],
    "reviewer_id": "aaes-eng"
  }
}
