SISKAMLING is a self-assessment security scanner for web applications, frontend build artifacts, and OpenAPI-described APIs. It combines deterministic artifact analysis, OWASP ZAP DAST, dependency audit ingestion, OpenAPI review, authenticated browser warm-up, OWASP Top 10 2025 tagging, and grouped Markdown reporting.
- Built web artifacts such as
dist/, including source maps, source map references, public env names, internal-looking endpoints, debug routes, and secret-like values. - Already-running live or staging sites through OWASP ZAP baseline/passive scanning.
- Local SPA previews after running configured install/build/preview commands.
- Authenticated web routes when form login is configured and Playwright can establish a browser session.
- OpenAPI definitions from local JSON/YAML files or remote OpenAPI URLs.
- APIs through optional ZAP API scan.
- Dependency audit output from a user-supplied command such as
npm audit --json,pnpm audit --json,yarn npm audit --json,bun audit, or a custom script.
- Python 3.10 or newer.
- Node.js/npm when using the
npxwrapper. - Docker when ZAP scans are enabled.
uvis recommended for cloned-repo usage.
The npx wrapper prefers uv when it is available. If uv is not available, it creates a local virtual environment under the user cache and installs Python dependencies there. It does not require global Python package installs.
From a published package:
npx siskamling init --profile artifact
npx siskamling validate-config --config siskamling.yaml
npx siskamling scan --config siskamling.yamlFrom a cloned repo with uv:
uv run siskamling init --profile artifact
uv run siskamling validate-config --config siskamling.yaml
uv run siskamling scan --config siskamling.yamlFrom a cloned repo through npm:
npx . version
npx . init --profile artifact --output siskamling.yaml
npx . validate-config --config siskamling.yamlThe compatibility wrapper remains available:
./run_analysis.shsiskamling init --profile artifact --output siskamling.yaml
siskamling validate-config --config siskamling.yaml
siskamling scan --config siskamling.yaml
siskamling report --raw reports/raw --normalized reports/normalized --out reports/final/Security_Report.md
siskamling versionscan runs the configured pipeline. report regenerates Markdown from existing artifacts without rebuilding, running Docker, or scanning a target again.
siskamling init --profile artifact
siskamling init --profile live
siskamling init --profile local-spa
siskamling init --profile api
siskamling init --profile authProfiles are templates only. They do not install dependencies, build the app, run Docker, or scan anything.
Use artifact when you already have a built directory such as dist/.
target:
name: example-app
mode: artifact
artifact:
dist_dir: dist
label: localUse live for an already-running local, staging, or live site.
target:
name: staging-app
mode: live
url: https://staging.example.comPassive ZAP scans are allowed in live mode by default. Remote active scans require allow_active_scan_on_remote: true.
Use local-spa when SISKAMLING should run local commands, build one artifact, start a preview server, and scan it.
target:
name: local-app
mode: local-spa
url: http://localhost:4173
app_dir: ../my-app
commands:
install: null
build: npm run build
preview: npm run preview -- --host 0.0.0.0 --port 4173
zap:
target_url: http://host.docker.internal:4173Use any package manager or command runner in target.commands. SISKAMLING executes the configured strings as trusted local commands.
Use api when you want deterministic OpenAPI analysis and optional ZAP API scan.
target:
mode: artifact
api:
enabled: true
openapi_path: ./openapi.yaml
openapi_url: null
base_url: https://api.example.com
zap:
enabled: false
active_scan: falseUse auth when the web scan should log in through a browser before ZAP runs.
target:
auth:
enabled: true
mode: form
login_url: https://example.com/login
username_env: SISKAMLING_AUTH_USERNAME
password_env: SISKAMLING_AUTH_PASSWORD
username_selector: input[name="email"]
password_selector: input[name="password"]
submit_selector: button[type="submit"]
success_url_pattern: /dashboardCredentials must come from environment variables. Do not commit credentials into config files.
Generate a starter file with siskamling init --profile ..., then edit the generated siskamling.yaml. A complete example looks like this:
target:
name: example-app
mode: local-spa # artifact | live | local-spa
url: http://localhost:4173
app_dir: ../my-app
allow_active_scan_on_remote: false
commands:
install: null
build: npm run build
preview: npm run preview -- --host 0.0.0.0 --port 4173
dependency_audit: npm audit --json
artifact:
dist_dir: dist
label: local
routes:
seeds_file: ./route-seeds.txt
auth:
enabled: false
mode: form
login_url: https://example.com/login
username_env: SISKAMLING_AUTH_USERNAME
password_env: SISKAMLING_AUTH_PASSWORD
username_selector: input[name="email"]
password_selector: input[name="password"]
submit_selector: button[type="submit"]
success_url_pattern: /dashboard
reports:
raw_dir: reports/raw
normalized_dir: reports/normalized
final_markdown: reports/final/Security_Report.md
zap:
target_url: http://host.docker.internal:4173
active_scan: false
image: ghcr.io/zaproxy/zaproxy:stable
alert_tags:
include: []
exclude: []
mode: report-only
api:
enabled: false
openapi_path: ./openapi.yaml
openapi_url: null
base_url: https://api.example.com
auth:
mode: none
env_token_name: API_TOKEN
header_name: Authorization
zap:
enabled: false
active_scan: falseImportant fields:
target.name: display name used in the report title.target.mode: one ofartifact,live, orlocal-spa.target.url: canonical application URL and the default URL passed to ZAP.target.app_dir: directory where configured commands run.target.allow_active_scan_on_remote: required before active scan can run against non-localhost targets.target.commands.install: optional install command.target.commands.build: optional single build command for this run.target.commands.preview: optional preview command forlocal-spa.target.commands.dependency_audit: optional dependency audit command.target.artifact.dist_dir: artifact directory to inspect.target.artifact.label: report label for the artifact, such aslocal,staging, orproduction.target.routes.seeds_file: optional route seed file used to warm or crawl known paths.target.reports.*: custom output paths for raw, normalized, and final report files.target.zap.active_scan: enables active ZAP scan when allowed by safety gates.
Route seed files are plain text, one path per line:
/
/login
/dashboard
/settings
/api/health
Local environment values are read from .env by default. Keep this file uncommitted:
SISKAMLING_TARGET_URL=http://localhost:4173
SISKAMLING_ZAP_TARGET_URL=http://host.docker.internal:4173
SISKAMLING_AUTH_USERNAME=
SISKAMLING_AUTH_PASSWORD=
SISKAMLING_ZAP_ACTIVE_SCAN=false
SISKAMLING_ZAP_ALERT_TAGS=target.url is the canonical application URL. It is passed to ZAP by default.
Use target.zap.target_url only when ZAP runs from Docker and needs a different network address:
target:
url: http://localhost:4173
zap:
target_url: http://host.docker.internal:4173In reports, Application URL shows target.url. ZAP scan URL is shown only when the effective ZAP URL differs.
Active scans are disabled by default. Enable them only for local, staging, or explicitly authorized systems.
For a remote target, this field must allow active scanning:
target:
allow_active_scan_on_remote: true
zap:
active_scan: trueIf this gate is not satisfied, SISKAMLING rejects the scan before running ZAP active checks.
SISKAMLING reports findings using OWASP Top 10 2025 categories and can filter or group by ZAP alert tags.
Runtime filter example:
SISKAMLING_ZAP_ALERT_TAGS=OWASP_2025_A10 siskamling scan --config siskamling.yamlConfig example:
target:
zap:
alert_tags:
include:
- OWASP_2025_A10
exclude: []
mode: report-onlySupported modes:
report-only: run the normal scan, then prioritize matching alert tags in the report.coverage: run the normal scan and show selected tag coverage even when there are no findings.active-policy: enable only active ZAP scanner rules derived from selected tags. This requirestarget.zap.active_scan: true.
The bundled alert tag catalog lives at config/zap-alert-tags/owasp-2025.json, so report enrichment does not require internet access.
When target.auth.enabled: true, SISKAMLING uses Playwright to log in before ZAP runs.
Behavior:
- credentials are read from environment variables only
- browser storage state and cookies are saved under
reports/raw/auth/ - configured route seeds are warmed with the authenticated browser context
- ZAP receives the authenticated Cookie header when login succeeds
- login failure is non-fatal and falls back to unauthenticated scanning with a scanner warning
Run with credentials:
SISKAMLING_AUTH_USERNAME=user@example.com \
SISKAMLING_AUTH_PASSWORD=example-password \
siskamling scan --config siskamling.yamlFor cloned repos, run through uv:
uv run --extra auth siskamling scan --config siskamling.yaml
uv run --extra auth playwright install chromiumFor npx, SISKAMLING bootstraps the Playwright Python package into a managed environment. If the browser binary is missing, install Chromium using the command shown in the scanner warning.
Enable deterministic OpenAPI analysis with either a local file or a remote URL:
target:
api:
enabled: true
openapi_path: ./openapi.yaml
openapi_url: null
base_url: https://api.example.com
auth:
mode: none
env_token_name: API_TOKEN
header_name: Authorization
zap:
enabled: false
active_scan: falseOpenAPI analysis flags candidate risks such as missing security requirements, unsafe unauthenticated methods, broad object identifiers, missing error responses, file uploads, permissive schemas, and undocumented auth schemes.
Remote active API scans require target.allow_active_scan_on_remote: true.
Default output layout:
reports/
raw/
normalized/
final/
Important artifacts:
reports/final/Security_Report.md: grouped Markdown report.reports/raw/scanner-warnings.json: non-fatal scanner warnings.reports/raw/zap-report.json,.xml,.html: raw ZAP outputs when ZAP runs.reports/raw/zap-api-report.json,.xml,.html: raw ZAP API outputs when API ZAP runs.reports/normalized/build-findings.json: deterministic artifact findings.reports/normalized/zap-findings.json: normalized web ZAP findings.reports/normalized/openapi-findings.json: normalized OpenAPI findings.reports/normalized/zap-api-findings.json: normalized API ZAP findings.
The Markdown report is intentionally grouped and concise. Raw detailed instances remain in reports/raw/ and reports/normalized/.
Quick overrides:
SISKAMLING_RUN_ZAP=false siskamling scan --config siskamling.yaml
SISKAMLING_RUN_DEPENDENCY_AUDIT=false siskamling scan --config siskamling.yaml
SISKAMLING_ZAP_ALERT_TAGS=OWASP_2025_A10 siskamling scan --config siskamling.yamlSupported public overrides:
SISKAMLING_CONFIG: config file path used by wrappers when--configis not passed.SISKAMLING_ENV: local env file path; defaults to.env.SISKAMLING_TARGET_URL: overridestarget.url, the canonical application URL.SISKAMLING_ZAP_TARGET_URL: overrides the effective URL passed to ZAP.SISKAMLING_RAW_DIR: overridestarget.reports.raw_dir.SISKAMLING_NORMALIZED_DIR: overridestarget.reports.normalized_dir.SISKAMLING_FINAL_MARKDOWN: overridestarget.reports.final_markdown.SISKAMLING_RUN_ZAP: set tofalseto skip web/API ZAP scans.SISKAMLING_RUN_DEPENDENCY_AUDIT: set tofalseto skip the configured dependency audit command.SISKAMLING_ZAP_ACTIVE_SCAN: overridestarget.zap.active_scan.SISKAMLING_ZAP_ALERT_TAGS: comma-separated alert tags to prioritize in the report.SISKAMLING_ZAP_EXCLUDE_ALERT_TAGS: comma-separated alert tags to exclude from the report.SISKAMLING_ZAP_ALERT_TAG_MODE: one ofreport-only,coverage, oractive-policy.SISKAMLING_ZAP_IMAGE: Docker image used for ZAP scans.SISKAMLING_API_OPENAPI_PATH: local OpenAPI file override.SISKAMLING_API_OPENAPI_URL: remote OpenAPI URL override.SISKAMLING_API_BASE_URL: API base URL used for OpenAPI analysis and API scan context.
Required command not found: docker: install Docker or setSISKAMLING_RUN_ZAP=false.ZAP_TARGET_UNREACHABLE: verifytarget.url,target.zap.target_url, preview server binding, and Docker host networking.remote active scan requires target.allow_active_scan_on_remote: true: active scanning remote systems requires explicit opt-in.- Auth falls back to unauthenticated: verify Playwright is installed, credentials exist in env vars, selectors match the login page, and
success_url_patternis correct. - OpenAPI parse failure: validate the JSON/YAML syntax and confirm the file path or remote URL is reachable.
- Dependency audit warning: run the configured audit command manually in
target.app_dirand confirm the package manager is installed. uvnot found in a cloned repo: installuv, or usenpx .to let the Node wrapper create a managed virtual environment.
bash -n run_analysis.sh
bash -n scripts/run_pipeline.sh
python3 -m compileall scripts siskamling
python3 scripts/smoke_test.py
python3 -m siskamling version
node bin/siskamling.js versionRun these before publishing an npm package:
npm test
npm pack --dry-run
python3 -m siskamling version
python3 -m siskamling init --profile artifact --output /tmp/siskamling.yaml --force