sast-analysis
Perform codebase analysis and architecture mapping as the first phase of a security assessment. Explores the tech stack,…
Detect Server-Side Template Injection (SSTI) vulnerabilities in a codebase using a three-phase approach: recon (find template rendering sites that use dynamic strings), batched verify (trace user input to those sites in parallel subagents, 3 candidates each), and merge
Claude Code
$ npx -y skills add utkusen/sast-skills --skill sast-ssti --agent claude-code
Codex
$ npx skills add utkusen/sast-skills --skill sast-ssti -a codex -y
Cursor
$ npx skills add utkusen/sast-skills --skill sast-ssti -a cursor -y
Gemini CLI
$ npx skills add utkusen/sast-skills --skill sast-ssti -a gemini-cli -y
GitHub Copilot
$ npx skills add utkusen/sast-skills --skill sast-ssti -a github-copilot -y
OpenCode
$ npx skills add utkusen/sast-skills --skill sast-ssti -a opencode -y
Windsurf
$ npx skills add utkusen/sast-skills --skill sast-ssti -a windsurf -y
name: sast-ssti description: >- Detect Server-Side Template Injection (SSTI) vulnerabilities in a codebase using a three-phase approach: recon (find template rendering sites that use dynamic strings), batched verify (trace user input to those sites in parallel subagents, 3 candidates each), and merge (consolidate batch results). Requires sast/architecture.md (run sast-analysis first). Outputs findings to sast/ssti-results.md. Use when asked to find SSTI or template injection bugs.
You are performing a focused security assessment to find Server-Side Template Injection vulnerabilities in a codebase. This skill uses a three-phase approach with subagents: **recon** (find candidate rendering sites where the template string is dynamic), **batched verify** (trace whether user input reaches each site's template argument, in parallel batches of 3), and **merge** (consolidate batch results into the final report).
**Prerequisites**: `sast/architecture.md` must exist. Run the analysis skill first if it doesn't.
---
Server-Side Template Injection occurs when user-supplied input is embedded directly into a template string that is then evaluated by a template engine. Unlike passing user data as *context variables* to a static template, SSTI means the user can write template syntax that the engine will execute — leading to arbitrary code execution, file read, or full server compromise.
The core pattern: *unvalidated user input is used as the template string passed to a template engine's render/compile/evaluate function.*
Do not flag these patterns:
render_template("profile.html", name=request.args.get("name"))
env.get_template("report.html").render(user=user_obj)
res.render("dashboard", { title: req.body.title })When you see these patterns, the code is likely **not vulnerable**:
**1. Static template file with dynamic context (most common safe pattern)**
# Flask — static template, user input only in context dict
return render_template("user_profile.html", username=request.args.get("name"))
# Express — static view name
res.render("dashboard", { user: req.user })**2. Allowlist validation for template names**
ALLOWED_TEMPLATES = {"invoice.html", "receipt.html", "summary.html"}
template_name = request.args.get("tmpl", "invoice.html")
if template_name not in ALLOWED_TEMPLATES:
abort(400)
return render_template(template_name)**3. Logic-less / sandboxed engines that don't support code execution**
// Mustache — logic-less, cannot execute arbitrary code even if template is user-supplied const output = Mustache.render(userTemplate, ctx); // lower risk, but still flag for review
---
# VULNERABLE: user input rendered as template string
@app.route('/greet')
def greet():
name = request.args.get('name', '')
template = f"<h1>Hello {name}!</h1>"
return render_template_string(template)
# Payload: ?name={{7*7}} → renders "49"
# RCE: ?name={{config.__class__.__init__.__globals__['os'].popen('id').read()}}
# SECURE: user input passed as context variable to a static template
@app.route('/greet')
def greet():
name = request.args.get('name', '')
return render_template("greet.html", name=name)# VULNERABLE: env.from_string with user-controlled template
@app.route('/preview')
def preview():
tmpl = request.form.get('template')
return Environment().from_string(tmpl).render()
# SECURE: load template from trusted file, pass user data as context
@app.route('/preview')
def previewA collection of agent skills that turn your LLM coding assistant into a fully functional SAST scanner to find vulnerabilities in your codebase. Works natively with Claude Code, Codex, Opencode, Cursor and any other assistant that supports agent skills.
Perform codebase analysis and architecture mapping as the first phase of a security assessment. Explores the tech stack,…
Detect business logic vulnerabilities in a codebase using a three-phase approach: threat modeling (domain analysis and attack…
Detect insecure file upload vulnerabilities in a codebase using a three-phase approach: discovery (find all upload sites),…
Detect GraphQL injection vulnerabilities in a codebase using a three-phase approach: recon (confirm GraphQL usage and find unsafe…
Detect hardcoded sensitive data (API keys, access tokens, private keys, passwords, etc.) in publicly accessible code — frontend…
Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…
Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys)…
Clean and finalize authorized natural-language text intended for readers by auditing suspicious invisible Unicode and rewriting…