Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/cycode-sast-pr-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: "Cycode SAST PR Scan (Delta)"

on:
pull_request:
branches: [main]
workflow_dispatch:

jobs:
cycode-sast-delta:
name: "SAST Delta Scan — PR Changes Only"
if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"

- name: Install Cycode CLI
run: pip install cycode

- name: Run Cycode SAST delta scan
env:
CYCODE_CLIENT_ID: ${{ secrets.CYCODE_CLIENT_ID }}
CYCODE_CLIENT_SECRET: ${{ secrets.CYCODE_CLIENT_SECRET }}
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE=${{ github.event.pull_request.base.sha }}
HEAD=${{ github.event.pull_request.head.sha }}
echo "Scanning PR delta: ${BASE}..${HEAD}"
cycode scan -t sast commit-history -r "${BASE}..${HEAD}" .
else
echo "Scanning last commit: HEAD~1"
cycode scan -t sast commit-history -r HEAD~1 .
fi
28 changes: 28 additions & 0 deletions .github/workflows/cycode-sast-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "Cycode SAST Scan"

on:
push:
branches: [main]
workflow_dispatch:

jobs:
cycode-sast:
name: "SAST Security Scan"
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"

- name: Install Cycode CLI
run: pip install cycode

- name: Run Cycode SAST scan
env:
CYCODE_CLIENT_ID: ${{ secrets.CYCODE_CLIENT_ID }}
CYCODE_CLIENT_SECRET: ${{ secrets.CYCODE_CLIENT_SECRET }}
run: cycode scan -t sast path ./vulnerable_apps/
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Examples of insecure Docker configurations and container practices:
- **Dockerfile.secrets-exposed** - Hardcoded secrets and credentials
- **Dockerfile.rootful-privileged** - Privileged containers running as root
- **Dockerfile.multistage-bad** - Insecure multi-stage builds
- **Dockerfile.n8n-vulnerable** - n8n with CVE-2026-21858 (CVSS 10.0)
- **docker-compose.vulnerable.yml** - Insecure Docker Compose configuration

### 🏗️ Vulnerable Terraform (`vulnerable_terraform/`)
Expand All @@ -60,6 +61,12 @@ Infrastructure-as-Code examples with security misconfigurations:
- **aws_iam_vulnerable.tf** - Overly permissive IAM policies and roles
- **aws_misc_vulnerable.tf** - Additional AWS security issues

### 📦 Vulnerable Packages (`vulnerable_packages/`)

Examples of applications using vulnerable open-source dependencies for SCA testing:

- **n8n-workflow/** - Workflow automation with n8n v1.100.0 (CVE-2026-21858, CVSS 10.0)

### 🌐 Vulnerable Web Applications (`vulnerable_apps/`)

Python web application examples demonstrating **OWASP Top 10 (2021)** vulnerabilities:
Expand Down
11 changes: 11 additions & 0 deletions config/api_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""API configuration for external service integrations."""

import os

# Slack integration
SLACK_BOT_TOKEN = "xoxb-7391528460193-5827461039285-kR4mXpLn7QdWtYvBs9jH3gFe"

# Database credentials
DB_HOST = "prod-db.internal.example.com"
DB_USER = "app_service"
DB_PASSWORD = "Pr0d_S3cure!P@ssw0rd_2025_xK9m"
97 changes: 97 additions & 0 deletions semgrep-rules/gha-dangerous-pr-target-checkout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
rules:

# ---------------------------------------------------------------
# Dangerous pull_request_target + PR code checkout
# ---------------------------------------------------------------
# Based on the official Semgrep rule:
# yaml.github-actions.security.pull-request-target-code-checkout
# Source: https://github.com/semgrep/semgrep-rules/blob/develop/yaml/github-actions/security/pull-request-target-code-checkout.yaml
#
# The pull_request_target event runs in the context of the BASE
# (target) repository, which means it has access to all repo
# secrets. Checking out the PR head then executes untrusted
# code from the fork with those secrets available.
#
# Covers all three trigger syntax variants:
# on:
# pull_request_target: ... (mapping)
# on: [push, pull_request_target] (list)
# on: pull_request_target (bare string)
#
# Covers all ref variants via metavariable-pattern:
# github.event.pull_request.head.sha
# github.event.pull_request.head.ref
# github.head_ref
# ---------------------------------------------------------------
- id: gha-pr-target-code-checkout
languages: [yaml]
message: >-
This GitHub Actions workflow uses `pull_request_target` and checks
out code from the incoming pull request. When using
`pull_request_target`, the Action runs in the context of the target
repository, which includes access to all repository secrets.
By checking out the incoming PR code, any build scripts
(npm install, make, pip install) execute attacker-controlled code
with access to those secrets, allowing an attacker to steal them.
Audit your workflow to ensure no incoming PR code is executed.
See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
severity: ERROR
metadata:
category: security
owasp:
- "A08:2021 - Software and Data Integrity Failures"
cwe:
- "CWE-829: Inclusion of Functionality from Untrusted Control Sphere"
references:
- https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
- https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
likelihood: MEDIUM
impact: HIGH
confidence: HIGH
patterns:
# Match any of the three trigger syntax forms
- pattern-either:
- pattern-inside: |
on:
...
pull_request_target: ...
...
...
- pattern-inside: |
on: [..., pull_request_target, ...]
...
- pattern-inside: |
on: pull_request_target
...
# Scope to within a job's steps block
- pattern-inside: |
jobs:
...
$JOBNAME:
...
steps:
...
# Match the checkout action with a ref parameter
- pattern: |
...
uses: "$ACTION"
with:
...
ref: $EXPR
# Ensure it's an actions/checkout action
- metavariable-regex:
metavariable: $ACTION
regex: actions/checkout@.*
# Ensure the ref expression references the incoming PR
- metavariable-pattern:
language: generic
metavariable: $EXPR
patterns:
- pattern-inside: "${{ ... }}"
- pattern-either:
- pattern: github.event.pull_request ...
- pattern: github.head_ref ...
paths:
include:
- "*.yml"
- "*.yaml"
125 changes: 125 additions & 0 deletions semgrep-rules/gha-excessive-permissions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
rules:

# ---------------------------------------------------------------
# Rule 1: Workflow-level permissions: write-all
# ---------------------------------------------------------------
# Catches the most obvious anti-pattern: granting the GITHUB_TOKEN
# full write access to every scope at the workflow level.
#
# Example match:
# permissions: write-all
# jobs:
# build:
# runs-on: ubuntu-latest
# ---------------------------------------------------------------
- id: gha-workflow-permissions-write-all
message: >
GitHub Actions workflow grants 'permissions: write-all' at the
workflow level, giving the GITHUB_TOKEN unrestricted write access
to all scopes (contents, packages, pull-requests, etc.).
Apply least-privilege by declaring only the permissions each job
actually needs.
severity: ERROR
languages: [yaml]
metadata:
cwe:
- "CWE-250: Execution with Unnecessary Privileges"
references:
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
category: security
patterns:
- pattern: |
permissions: write-all
- pattern-not-inside: |
jobs:
...
$JOB:
...
permissions: write-all
...
paths:
include:
- "*.yml"
- "*.yaml"

# ---------------------------------------------------------------
# Rule 2: Job-level permissions: write-all
# ---------------------------------------------------------------
# Same problem scoped to a single job. Still overly broad since
# it grants write to every scope for that job.
#
# Example match:
# jobs:
# deploy:
# permissions: write-all
# runs-on: ubuntu-latest
# ---------------------------------------------------------------
- id: gha-job-permissions-write-all
message: >
GitHub Actions job grants 'permissions: write-all', giving the
GITHUB_TOKEN unrestricted write access for this job. Narrow the
permissions to only those required (e.g., contents: read).
severity: WARNING
languages: [yaml]
metadata:
cwe:
- "CWE-250: Execution with Unnecessary Privileges"
references:
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
category: security
pattern: |
jobs:
...
$JOB:
...
permissions: write-all
...
paths:
include:
- "*.yml"
- "*.yaml"

# ---------------------------------------------------------------
# Rule 3: Workflow-level broad write scopes
# ---------------------------------------------------------------
# Catches explicit per-scope write grants at the workflow level
# that are commonly over-provisioned. The metavariable $SCOPE
# matches any scope key (contents, packages, etc.) set to write.
#
# Example match:
# permissions:
# contents: write
# packages: write
# pull-requests: write
# ---------------------------------------------------------------
- id: gha-workflow-broad-write-permissions
message: >
GitHub Actions workflow grants write access to scope '$SCOPE'
at the workflow level. Verify this is required. Prefer setting
permissions at the job level so each job gets only what it needs.
severity: WARNING
languages: [yaml]
metadata:
cwe:
- "CWE-250: Execution with Unnecessary Privileges"
references:
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication
category: security
patterns:
- pattern: |
permissions:
...
$SCOPE: write
...
- pattern-not-inside: |
jobs:
...
$JOB:
...
permissions:
...
...
paths:
include:
- "*.yml"
- "*.yaml"
47 changes: 47 additions & 0 deletions vulnerable_dockerfiles/Dockerfile.n8n-vulnerable
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Vulnerable n8n Container
# This Dockerfile uses a vulnerable version of n8n affected by CVE-2026-21858

FROM n8nio/n8n:1.100.0

LABEL maintainer="demo@example.com"
LABEL description="Workflow automation service"
LABEL vulnerability="CVE-2026-21858"

# Environment configuration
ENV N8N_BASIC_AUTH_ACTIVE=false
ENV N8N_HOST=0.0.0.0
ENV N8N_PORT=5678
ENV N8N_PROTOCOL=http
ENV GENERIC_TIMEZONE=UTC

# Expose the n8n port
EXPOSE 5678

# Start n8n
CMD ["n8n", "start"]

# =============================================================================
# VULNERABILITY INFORMATION
# =============================================================================
#
# CVE-2026-21858: Critical Content-Type Confusion RCE in n8n
#
# Affected: n8n versions >= 1.65.0 and < 1.121.0
# CVSS Score: 10.0 (Critical)
# CWE: CWE-20 (Improper Input Validation)
#
# The n8n:1.100.0 base image contains a critical vulnerability in Form Webhook
# handling that allows unauthenticated attackers to:
# - Read arbitrary files from the container
# - Extract database and session secrets
# - Forge administrator sessions
# - Execute arbitrary commands
#
# REMEDIATION:
# Update to a fixed version:
# FROM n8nio/n8n:1.121.0
#
# References:
# - https://nvd.nist.gov/vuln/detail/CVE-2026-21858
# - https://github.com/n8n-io/n8n/security/advisories/GHSA-v4pr-fm98-w9pg
# =============================================================================
Loading