Snyk Hardening Guide
AppSec platform security for service accounts, SCM integrations, and Broker configs
Overview
Snyk provides developer security for vulnerability scanning across code, dependencies, containers, and IaC. REST API, CLI tokens, and SCM integrations access source code repositories and vulnerability data. Compromised access exposes vulnerability findings and potentially enables code access through integrations.
Intended Audience
- Security engineers managing AppSec tools
- DevSecOps administrators
- GRC professionals assessing development security
- Third-party risk managers evaluating security scanning tools
How to Use This Guide
- L1 (Crawl): Essential controls for all organizations
- L2 (Walk): Enhanced controls for security-sensitive environments
- L3 (Run): Strictest controls for regulated industries
Scope
This guide covers Snyk security configurations including authentication, access controls, and integration security.
Table of Contents
1. Authentication & Access Controls
1.1 Enforce SSO with MFA
Profile Level: L1 (Crawl) NIST 800-53: IA-2(1)
Description
Require SAML SSO through your corporate identity provider and enforce multi-factor authentication for every user who accesses the Snyk platform.
Rationale
Why This Matters:
- Centralizes Snyk authentication in your IdP so MFA, conditional access, and session policies apply to every login
- Local or password-only logins bypass corporate identity controls and are prime targets for credential stuffing and phishing
- SSO with automated deprovisioning removes departed users’ access immediately, preventing orphaned accounts from reaching vulnerability data
- Snyk holds your organization’s known-vulnerability inventory and SCM connections, so a single compromised login can reveal exactly where you are exploitable
Attack Prevented: Credential theft, phishing, MFA bypass, orphaned-account access
ClickOps Implementation
Step 1: Configure SAML SSO (Business/Enterprise)
- Navigate to: Settings → SSO
- Configure SAML IdP
- Enable: Require SSO
Step 2: Enable MFA (Non-SSO)
- Configure MFA through account settings
- Enforce for all users
1.2 Role-Based Access
Profile Level: L1 (Crawl) NIST 800-53: AC-3, AC-6
Description
Assign Snyk group and organization members the least-privileged role required for their function instead of granting broad administrative access by default.
Rationale
Why This Matters:
- Least-privilege roles limit how much a single compromised or insider account can change, export, or expose
- Group Admin and Org Admin can alter integrations, ignore policies, and member access, so these rights should be tightly held
- Scoping collaborators to view-and-test prevents accidental or malicious changes to scanning configuration and findings
- Clear role separation makes access reviews and audit attribution far easier across many organizations
Attack Prevented: Privilege escalation, insider misuse, unauthorized configuration changes, lateral movement
ClickOps Implementation
Step 1: Define Roles
| Role | Permissions |
|---|---|
| Group Admin | Full organization access |
| Org Admin | Organization management |
| Org Collaborator | View and test projects |
| Org Custom | Custom permissions |
Step 2: Configure Organization Access
- Navigate to: Settings → Members
- Assign appropriate roles
- Use least privilege
2. Integration Security
2.1 Secure Service Account Tokens
Profile Level: L1 (Crawl) NIST 800-53: IA-5
Description
Choose the right service-account credential type for every non-interactive Snyk integration, and manage those credentials on a defined lifecycle. Snyk offers three service-account authentication types with materially different security properties — API key, access token, and OAuth 2.0 — and the choice determines whether the credential ever expires.
Rationale
Why This Matters:
- Service account credentials are non-interactive and bypass MFA, so a leaked credential grants direct API access with the service account’s full role
- API keys never expire. Snyk documents the API key service account as a legacy type and explicitly states it is not recommended — an API key leaked into a CI log or repository is a permanent credential until someone notices and deletes the account
- Access tokens cap out at a one-year maximum expiry, and Snyk documents no in-place rotation: when an access token expires you must create a new service account and re-plumb every consumer, so the rotation has to be planned rather than discovered at expiry
- OAuth 2.0 service accounts issue short-lived tokens with automated refresh, which is why they are the recommended type for CI/CD and any long-running integration
- Snyk credentials can read vulnerability findings and drive SCM operations, so exposure reveals exploitable weaknesses and integration reach
Attack Prevented: Token theft, credential leakage in CI/CD, standing-credential abuse, unauthorized data export
Attack Scenario: Exposed API token enables vulnerability data export; attackers gain insight into exploitable vulnerabilities before patches.
ClickOps Implementation
Step 1: Choose the Credential Type
| Type | Expiry | Rotation | Snyk guidance |
|---|---|---|---|
| API key | Never expires | Manual only (delete + recreate) | Legacy — explicitly not recommended |
| Access token | Configurable, 1 year maximum | No in-place rotation — requires a new service account | Acceptable where OAuth is not supported; plan around the 1-year ceiling |
| OAuth 2.0 | Short-lived access token | Automated refresh | Recommended — use for CI/CD and all new integrations |
Default to OAuth 2.0. Never create API-key service accounts for new integrations, and treat any existing API-key service account as a standing credential to be migrated. See Choose a service account type.
Step 2: Audit Service Accounts
- Navigate to: Settings → Service accounts
- Review all service accounts and record the credential type of each
- Remove unused accounts
- Flag every API-key service account for migration to OAuth 2.0
Step 3: Credential Lifecycle
- Create one service account per CI/CD pipeline or integration — never share credentials across consumers
- Assign the least-privileged role the integration needs
- For access tokens, diary the expiry date and schedule the replacement service account before it lapses (there is no in-place renewal)
- Store credentials in a secrets manager; never commit them or echo them in pipeline logs
Code Implementation
Code Pack: API Script
: "${SNYK_TOKEN:?Set SNYK_TOKEN to a Snyk API token with admin access}"
SNYK_API="${SNYK_API:-https://api.snyk.io}"
SNYK_API_VERSION="${SNYK_API_VERSION:-2024-06-10}"
# Audit one scope: "groups <group_id>" or "orgs <org_id>"
audit_service_accounts() {
local scope="$1" scope_id="$2"
echo "== Service accounts for ${scope}/${scope_id} =="
curl -sf \
--header "Authorization: token ${SNYK_TOKEN}" \
--header "Content-Type: application/vnd.api+json" \
"${SNYK_API}/rest/${scope}/${scope_id}/service_accounts?version=${SNYK_API_VERSION}" \
| jq -r '
# Service account records carry: id, name, auth_type, role_id,
# access_token_expires_at, access_token_ttl_seconds.
# auth_type is one of: access_token, api_key,
# oauth_client_secret, oauth_private_key_jwt.
[.. | objects | select(.auth_type?)] | .[] |
[ .name,
.auth_type,
(.access_token_expires_at // "n/a"),
(if .auth_type == "api_key" then
"FAIL: legacy API key - never expires, migrate to OAuth 2.0"
elif .auth_type == "access_token" then
"WARN: 1-year max expiry, no in-place rotation - plan replacement"
else
"PASS: OAuth 2.0 short-lived credential"
end)
] | @tsv'
}
# Group-level service accounts, then each org you operate:
[ -n "${SNYK_GROUP_ID:-}" ] && audit_service_accounts "groups" "${SNYK_GROUP_ID}"
[ -n "${SNYK_ORG_ID:-}" ] && audit_service_accounts "orgs" "${SNYK_ORG_ID}"
# Remove a flagged legacy service account once its workload is migrated
# to an OAuth 2.0 service account (deletion also kills its API key).
# DELETE /rest/orgs/{org_id}/service_accounts/{service_account_id}
# DELETE /rest/groups/{group_id}/service_accounts/{service_account_id}
delete_service_account() {
local scope="$1" scope_id="$2" sa_id="$3"
curl -sf -X DELETE \
--header "Authorization: token ${SNYK_TOKEN}" \
"${SNYK_API}/rest/${scope}/${scope_id}/service_accounts/${sa_id}?version=${SNYK_API_VERSION}"
echo "Deleted service account ${sa_id} from ${scope}/${scope_id}"
}
2.2 SCM Integration Security
Profile Level: L1 (Crawl) NIST 800-53: CM-7
Description
Review and restrict Snyk’s source-code-management integrations so each connection has only the repository access it needs, and route private-repo access through the Snyk Broker. Snyk ships the Broker in two deployment models — Universal Broker and Classic Broker — and new deployments should target Universal Broker.
Rationale
Why This Matters:
- SCM integrations grant Snyk read access to source repositories, so an over-scoped or stale connection widens what a platform compromise can reach
- The Snyk Broker keeps private repositories behind your perimeter and brokers only approved requests instead of exposing direct SCM credentials — Snyk documents that with Broker, “credentials remain within your network and are never stored by or transmitted to Snyk”
- Universal Broker consolidates many connection types (GitHub, GitLab, Artifactory, Jira, container registry) behind a single client or set of replicas, so there is one hardened egress path to govern instead of one Broker deployment per integration
- Classic Broker uses per-integration deployments with
accept.jsonrequest filters that constrain which endpoints and operations the Broker permits, enforcing least privilege at the integration layer - Limiting repository scope contains the impact if a token or integration is abused, preventing access to unrelated codebases
Attack Prevented: Source code exposure, over-scoped integration abuse, supply chain reconnaissance, credential leakage
Changed default (April 2026): Snyk Broker now runs in high-availability mode by default. Deployments provisioned before this change may still be running single-instance; confirm your replica configuration rather than assuming the old default. Source: Snyk What’s New.
ClickOps Implementation
Step 1: Review Integrations
- Navigate to: Settings → Integrations
- Review SCM connections
- Limit repository access
Step 2: Choose a Broker Deployment Model (Enterprise)
| Model | Shape | Use it for |
|---|---|---|
| Universal Broker | One Broker client (or replica set) serving many connection types — GitHub, GitLab, Artifactory, Jira, container registry | New deployments. Fewer moving parts, one egress path, centrally managed connections |
| Classic Broker | One Broker deployment per integration type, each with its own accept.json filter file |
Existing estates already running per-integration Brokers |
Step 3: Harden the Broker Deployment
- Deploy the Broker inside your network so SCM credentials never leave your perimeter
- Restrict the permitted request set —
accept.jsonfilters in Classic Broker, per-connection configuration in Universal Broker - Limit exposed endpoints to the minimum the Snyk integration requires
- Verify high-availability replica count matches your availability requirement
3. Data Security
3.1 Project Visibility
Profile Level: L1 (Crawl) NIST 800-53: AC-21
Description
Configure project visibility, vulnerability-detail access, and report/export permissions so only authorized users can view sensitive findings.
Rationale
Why This Matters:
- Vulnerability findings describe exactly where your software is exploitable, so over-broad visibility hands attackers a roadmap
- Limiting who can view issue details and share findings keeps sensitive security data on a need-to-know basis
- Controlling report generation and export prevents bulk exfiltration of findings outside monitored channels
- Auditing report access lets you detect unusual harvesting of vulnerability data before it is misused
Attack Prevented: Information disclosure, vulnerability reconnaissance, data exfiltration, insider leakage
ClickOps Implementation
Step 1: Configure Project Settings
- Set appropriate project visibility
- Limit who can view vulnerability details
- Control issue sharing
Step 2: Report Access
- Limit report generation
- Control export permissions
- Audit report access
3.2 Ignore Policy
Profile Level: L2 (Walk) NIST 800-53: CM-7
Description
Govern how vulnerabilities are ignored by requiring a documented reason, an expiration date, and periodic review of all suppressed findings.
Rationale
Why This Matters:
- Unbounded ignores silently suppress real vulnerabilities, letting exploitable issues ship while dashboards appear clean
- Requiring a reason and approver creates accountability and an audit trail for every accepted risk
- Expiration forces re-evaluation so a temporary exception does not quietly become permanent blindness
- Auditing ignored issues catches abuse where suppression is used to bypass security gates rather than manage genuine false positives
Attack Prevented: Risk-acceptance abuse, suppressed-vulnerability exploitation, security-gate bypass, audit evasion
Implementation
Step 1: Ignore Workflow
- Require reason for ignores
- Set ignore expiration
- Audit ignored vulnerabilities
Code Implementation
Code Pack: CLI Script
# Never ignore without a reason and a bounded expiry. Left alone, the CLI
# default expiry is 30 days — set it explicitly so the review date is a
# decision, not an accident. Expiry format: YYYY-MM-DD.
ISSUE_ID="${1:?Usage: $0 <snyk-issue-id> <expiry YYYY-MM-DD> <reason...>}"
EXPIRY="${2:?Usage: $0 <snyk-issue-id> <expiry YYYY-MM-DD> <reason...>}"
shift 2
REASON="${*:?A human-readable reason is required}"
snyk ignore \
--id="${ISSUE_ID}" \
--expiry="${EXPIRY}" \
--reason="${REASON} (approved-by: ${SNYK_IGNORE_APPROVER:-unset})"
# The ignore lands in the repo's .snyk policy file as:
# ignore:
# '<ISSUE_ID>':
# - '*':
# reason: <REASON>
# expires: <EXPIRY>
# Audit pass for review/CI: surface every suppression with its reason and
# expiry so unbounded or unjustified ignores are visible in code review.
POLICY_FILE="${SNYK_POLICY_FILE:-.snyk}"
if [ -f "${POLICY_FILE}" ]; then
echo "== Suppression entries in ${POLICY_FILE} =="
grep -nE "reason:|expires:" "${POLICY_FILE}" || echo "No ignores recorded"
IGNORES=$(grep -cE "^ignore:" "${POLICY_FILE}" || true)
REASONS=$(grep -cE "reason:" "${POLICY_FILE}" || true)
EXPIRIES=$(grep -cE "expires:" "${POLICY_FILE}" || true)
echo "ignore blocks: ${IGNORES} | reasons recorded: ${REASONS} | expiries recorded: ${EXPIRIES}"
if [ "${REASONS}" -ne "${EXPIRIES}" ]; then
echo "WARN: reason/expiry counts differ - review ${POLICY_FILE} for unbounded ignores"
fi
fi
4. Monitoring & Detection
4.1 Audit Logs (Enterprise)
Profile Level: L1 (Crawl) NIST 800-53: AU-2, AU-3
Description
Review Snyk audit logs and forward them to your SIEM to retain a record of user and administrative activity across the platform. Snyk’s audit logs are an Enterprise-plan capability with a 90-day rolling retention window, and they exclude login and logout events — both facts drive how the control must be implemented.
Rationale
Why This Matters:
- Audit logs provide the authoritative record of who changed integrations, roles, ignore policies, and tokens
- Retention is a rolling 90 days. Any investigation, compliance evidence, or retrospective beyond that window is impossible from Snyk alone, which makes SIEM forwarding mandatory rather than optional
- Login and logout events are excluded from the audit-log endpoints. Authentication activity must be reconstructed from your identity provider’s logs — treat the IdP as the system of record for Snyk sign-in, and correlate it with Snyk audit events in the SIEM
- Without centralized logging, account compromise and configuration tampering can go undetected until damage is done
- Reviewing activity supports incident response, forensics, and compliance evidence for access and change controls
Attack Prevented: Undetected account compromise, configuration tampering, audit gaps, delayed incident response
Prerequisites
- Enterprise plan — audit logs are not available on Free, Team, or Business
ClickOps Implementation
Step 1: Access Audit Logs
- Navigate to: Settings → Audit logs
- Review user activities
Step 2: Forward to SIEM Before the 90-Day Window Closes
- Pull group- and org-level audit events via the audit logs API
- Schedule collection at an interval well inside the 90-day retention window so no events age out uncollected
- Retain forwarded events in the SIEM per your own retention policy — Snyk will not hold them
Step 3: Fill the Authentication Gap from the IdP
- Forward Snyk SSO sign-in and sign-out events from your identity provider (the Snyk audit endpoints do not carry them)
- Correlate IdP authentication events with Snyk audit events to reconstruct a complete session-to-action trail
Code Implementation
Code Pack: API Script
: "${SNYK_TOKEN:?Set SNYK_TOKEN to a Snyk API token with admin access}"
SNYK_API="${SNYK_API:-https://api.snyk.io}"
SNYK_API_VERSION="${SNYK_API_VERSION:-2024-06-10}"
# Collection window — run at least daily; events age out after 90 days.
FROM="${SNYK_AUDIT_FROM:-$(date -u -d '1 day ago' +%Y-%m-%d)}"
TO="${SNYK_AUDIT_TO:-$(date -u +%Y-%m-%d)}"
OUT_DIR="${SNYK_AUDIT_OUT_DIR:-./snyk-audit-logs}"
mkdir -p "${OUT_DIR}"
# Export one scope: "orgs <org_id>" or "groups <group_id>".
# GET /rest/orgs/{org_id}/audit_logs/search
# GET /rest/groups/{group_id}/audit_logs/search
# Optional params: from, to, size, cursor, events, exclude_events.
export_audit_logs() {
local scope="$1" scope_id="$2"
local out="${OUT_DIR}/${scope}-${scope_id}-${FROM}_${TO}.json"
local url="${SNYK_API}/rest/${scope}/${scope_id}/audit_logs/search?version=${SNYK_API_VERSION}&from=${FROM}&to=${TO}&size=100"
[ -n "${SNYK_AUDIT_CURSOR:-}" ] && url="${url}&cursor=${SNYK_AUDIT_CURSOR}"
curl -sf \
--header "Authorization: token ${SNYK_TOKEN}" \
--header "Content-Type: application/vnd.api+json" \
"${url}" | jq '.' > "${out}"
echo "Exported ${scope}/${scope_id} audit logs ${FROM}..${TO} -> ${out}"
}
# Pull group-level events (role, policy, membership changes) and each
# org's events, then forward the JSON files to your SIEM.
[ -n "${SNYK_GROUP_ID:-}" ] && export_audit_logs "groups" "${SNYK_GROUP_ID}"
[ -n "${SNYK_ORG_ID:-}" ] && export_audit_logs "orgs" "${SNYK_ORG_ID}"
Detection Focus
Appendix A: Edition Compatibility
| Control | Free | Team | Business | Enterprise |
|---|---|---|---|---|
| SAML SSO | ❌ | ❌ | ✅ | ✅ |
| SCIM | ❌ | ❌ | ❌ | ✅ |
| Audit Logs | ❌ | ❌ | ❌ | ✅ |
| Service Accounts | ❌ | ❌ | ✅ | ✅ |
Appendix B: References
Official Snyk Documentation:
- User Docs
- What’s New (release notes)
- SSO Setup Guide
- Service Accounts
- Choose a Service Account Type
- Snyk Broker
- Universal Broker
- Classic Broker
- Vulnerability Disclosure Program
API Documentation:
Compliance Frameworks:
- ISO 27001, ISO 27017, SOC 2 Type II — via Trust Center
- Platform Compliance
Security Incidents:
- No major public incidents involving Snyk identified
Changelog
| Date | Version | Maturity | Changes | Author |
|---|---|---|---|---|
| 2026-08-08 | 0.2.1 | draft | Added api Code Packs for §2.1 (service-account credential-type audit + legacy-key deletion via the REST service_accounts endpoints) and §4.1 (org/group audit-log export via audit_logs/search inside the 90-day window), plus a cli Code Pack for §3.2 (snyk ignore with mandatory reason and expiry, .snyk suppression audit), all verified against docs.snyk.io API and CLI references | Claude Code (Fable 5) |
| 2026-08-08 | 0.2.0 | draft | Currency pass (Tier 1 only): rewrote 2.1 for the three service-account credential types (API key never expires and is not recommended; access token 1-year max with no in-place rotation; OAuth 2.0 recommended); added Universal vs Classic Broker and the April 2026 Broker high-availability default to 2.2; documented Enterprise-only audit logs, 90-day rolling retention, and the login/logout exclusion in 4.1; repaired rotted docs.snyk.io links to the platform-administration tree and removed Trust Center / marketing pages from Appendix B. Tier 3/4 research sweep out of scope this pass. | Claude Code (Opus 4.8) |
| 2025-12-14 | 0.1.0 | draft | Initial Snyk hardening guide | Claude Code (Opus 4.5) |
Contributing
Found an issue or want to improve this guide?
- Report outdated information: Open an issue with tag
content-outdated - Propose new controls: Open an issue with tag
new-control - Submit improvements: See Contributing Guide