sast-xss
Detect Cross-Site Scripting (XSS) vulnerabilities in a codebase using a three-phase approach: recon (find HTML/JS/DOM sink sites), batched verify (trace user input to sinks in parallel subagents, 3 sink sites each), and merge (consolidate batch results).
Install / Use
npx skills add utkusen/sast-skills --skill sast-xssInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
SecuritySupported Platforms
Our assessment of sast-xss
sast-xss scores 89/100 on our quality scale, 495th of 971 Security skills we index.
Its SKILL.md is 28 KB long, well organised into 41 sections with 25 code examples: a thorough specification that gives an agent plenty to work with.
With 1,321 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 98/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
sast-xss compared with similar skills
All 4 of these similar skills score higher than sast-xss; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| sast-xss (this skill)by utkusen | 89 | 1.3k | 6mo ago | SKILL.md |
| algorithmic-artby anthropics | 100 | 177.9k | 8d ago | SKILL.md |
| pptxby anthropics | 100 | 177.9k | 8d ago | SKILL.md |
| designby nextlevelbuilder | 100 | 130.2k | 9d ago | SKILL.md |
| ui-ux-pro-maxby nextlevelbuilder | 100 | 130.2k | 9d ago | SKILL.md |
Frequently asked questions
- How do I install sast-xss?
- Run
npx skills add utkusen/sast-skills --skill sast-xss. The install tabs above show the steps for each supported agent. - Which AI agents does sast-xss work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is sast-xss safe to use?
- It is MIT-licensed and scores 98/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is sast-xss still maintained?
- The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
Skill content
View source on GitHubname: sast-xss description: >- Detect Cross-Site Scripting (XSS) vulnerabilities in a codebase using a three-phase approach: recon (find HTML/JS/DOM sink sites), batched verify (trace user input to sinks in parallel subagents, 3 sink sites each), and merge (consolidate batch results). Requires sast/architecture.md (run sast-analysis first). Outputs findings to sast/xss-results.md. Use when asked to find XSS or cross-site scripting bugs.
Cross-Site Scripting (XSS) Detection
You are performing a focused security assessment to find Cross-Site Scripting vulnerabilities in a codebase. This skill uses a three-phase approach with subagents: recon (find sink sites), batched verify (trace taint for parallel batches of up to 3 sinks each), and merge (consolidate batch results into one report).
Prerequisites: sast/architecture.md must exist. Run the analysis skill first if it doesn't.
What is XSS
XSS occurs when user-supplied input is incorporated into a web page's HTML, JavaScript, or DOM without proper escaping or sanitization. This allows attackers to inject and execute arbitrary scripts in victims' browsers, leading to session hijacking, credential theft, defacement, and malware distribution.
The core pattern: unescaped, unsanitized user input reaches an HTML/JS output sink.
XSS Types
- Reflected XSS: User input is immediately echoed back in the HTTP response (e.g., a search term rendered directly into the page HTML).
- Stored XSS: User input is saved to persistent storage (database, file) and later rendered in HTML for other users.
- DOM-based XSS: Client-side JavaScript reads from an attacker-controlled source (
location.search,location.hash,document.cookie) and writes to a dangerous DOM sink (innerHTML,eval,document.write) without server involvement.
What XSS IS
Server-side HTML sinks — rendering user data into HTML responses without escaping:
- Python/Jinja2:
{{ var | safe }},{% autoescape off %}...{{ var }}...{% endautoescape %} - Python/Django:
mark_safe(var),format_html(...)with%sand unescaped input,{{ var | safe }}in templates - Python/Flask:
Markup(var),render_template_string(f"...{var}...") - PHP:
echo $var,print $var,<?= $var ?>withouthtmlspecialchars() - Ruby/Rails:
raw(var),var.html_safe,<%= raw var %>,content_tagwith.html_safe - Java/JSP:
<%= var %>,${var}without<c:out>orfn:escapeXml() - Java/Thymeleaf:
th:utext="${var}"(unescaped),[(${var})] - Go/html-template misuse: using
template.HTML(var),template.JS(var),template.URL(var)to bypass auto-escaping - C#/Razor:
@Html.Raw(var),MvcHtmlString.Create(var) - Node.js/EJS:
<%- var %>(unescaped), vs<%= var %>(safe) - Node.js/Handlebars:
{{{ var }}}(triple-brace, unescaped) - Node.js/Pug:
!{var}(unescaped) - Express:
res.send("<html>..." + var + "..."),res.write("<p>" + var + "</p>")
Client-side DOM sinks — JavaScript writing user-controlled data to the DOM unsafely:
element.innerHTML = varelement.outerHTML = vardocument.write(var),document.writeln(var)element.insertAdjacentHTML('beforeend', var)- jQuery:
$(element).html(var),$(element).append(var)(when var contains HTML),$('<div>' + var + '</div>') - React:
dangerouslySetInnerHTML={{ __html: var }} - Angular:
[innerHTML]="var",bypassSecurityTrustHtml(var),bypassSecurityTrustScript(var),bypassSecurityTrustUrl(var) - Vue:
v-html="var"
JavaScript execution sinks — user-controlled data evaluated as code:
eval(var)setTimeout(var, delay)/setInterval(var, delay)whenvaris a stringnew Function(var)()element.setAttribute('onclick', var),element.setAttribute('href', 'javascript:' + var)location.href = var,location.replace(var),location.assign(var)(when var is user-controlled and can bejavascript:...)element.src = var,element.action = var(script injection viajavascript:URIs)scriptElement.text = var,scriptElement.textContent = var
DOM-based sources — attacker-controlled inputs read by client-side JavaScript:
location.search(URL query string)location.hash(URL fragment)location.hrefdocument.referrerdocument.URL,document.documentURIdocument.cookiepostMessageevent data (event.data)window.namelocalStorage.getItem(...),sessionStorage.getItem(...)(if populated from URL or postMessage)
What XSS is NOT
Do not flag these as XSS:
- CSRF: Forging requests on behalf of a user — a separate vulnerability class
- SQLi via XSS: Injecting SQL through an XSS vector — the SQL injection itself is the primary finding
- Clickjacking: Embedding pages in iframes — different vulnerability class
- Header injection: Injecting newlines into HTTP response headers — separate class (HTTP Response Splitting)
- Safe template output: Auto-escaped
{{ var }}in Jinja2/Django/Twig/Blade/Handlebars double-brace syntax with auto-escaping on — these are safe textContent/innerText: These write plain text only; no HTML parsing occurs — safe
Patterns That Prevent XSS
When you see these patterns, the code is likely not vulnerable:
1. Context-aware auto-escaping (most template engines default)
# Jinja2 / Django (auto-escape on by default)
{{ var }} # HTML-escaped → safe
# EJS
<%= var %> # HTML-escaped → safe
# Handlebars
{{ var }} # HTML-escaped → safe
# Pug
= var # HTML-escaped → safe
# Thymeleaf
th:text="${var}" # HTML-escaped → safe
# Razor (C#)
@var # HTML-encoded → safe
2. Explicit escaping before output
// PHP
echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8');
# Rails
<%= h(var) %>
<%= ERB::Util.html_escape(var) %>
// JSP with JSTL
<c:out value="${var}"/>
// or fn:escapeXml()
${fn:escapeXml(var)}
// html/template — auto-escapes by context (HTML, JS, URL, CSS)
{{.Var}} // safe inside html/template
3. DOM manipulation using safe properties
element.textContent = userInput; // plain text, no HTML parsing — safe
element.innerText = userInput; // plain text — safe
4. Sanitization with an allowlisted HTML library
// DOMPurify
element.innerHTML = DOMPurify.sanitize(userInput);
// sanitize-html with strict config
const clean = sanitizeHtml(userInput, { allowedTags: [], allowedAttributes: {} });
5. React / Angular / Vue auto-escaping
// React JSX — auto-escaped
return <div>{userInput}</div>;
<!-- Angular — auto-escaped -->
<div>{{ userInput }}</div>
<!-- Vue — auto-escaped -->
<div>{{ userInput }}</div>
Vulnerable vs. Secure Examples
Python — Flask / Jinja2
# VULNERABLE: Markup() bypasses Jinja2 auto-escaping
@app.route('/greet')
def greet():
name = request.args.get('name', '')
return render_template_string(f"<h1>Hello, {name}!</h1>") # raw f-string, no template escaping
# VULNERABLE: mark_safe equivalent
@app.route('/profile')
def profile():
bio = request.args.get('bio', '')
return render_template('profile.html', bio=Markup(bio)) # Markup() marks it as safe, bypassing escaping
# SECURE: use template with auto-escaping (never pass Markup around user input)
@app.route('/greet')
def greet():
name = request.args.get('name', '')
return render_template('greet.html', name=name) # template: {{ name }} — auto-escaped
Python — Django
# VULNERABLE: mark_safe() with user input
def user_bio(request):
bio = request.GET.get('bio', '')
safe_bio = mark_safe(bio) # user input bypasses Django's auto-escaping
return render(request, 'bio.html', {'bio': safe_bio})
# SECURE: pass raw string; template handles escaping
def user_bio(request):
bio = request.GET.get('bio', '')
return render(request, 'bio.html', {'bio': bio}) # template: {{ bio }} — auto-escaped
PHP
// VULNERABLE: echo without escaping
function showUsername($username) {
echo "<p>Welcome, " . $username . "</p>";
}
// SECURE: htmlspecialchars
function showUsername($username) {
echo "<p>Welcome, " . htmlspecialchars($username, ENT_QUOTES, 'UTF-8') . "</p>";
}
Node.js — Express (string concatenation)
// VULNERABLE: user input concatenated into HTML response
app.get('/search', (req, res) => {
const query = req.query.q;
res.send(`<h1>Results for: ${query}</h1>`);
});
// SECURE: use a template engine with auto-escaping, or escape manually
const escapeHtml = require('escape-html');
app.get('/search', (req, res) => {
const query = req.query.q;
res.send(`<h1>Results for: ${escapeHtml(query)}</h1>`);
});
Node.js / EJS
<!-- VULNERABLE: unescaped output -->
<div><%- userInput %></div>
<!-- SECURE: escaped output -->
<div><%= userInput %></div>
Node.js / Handlebars
<!-- VULNERABLE: triple-brace, unescaped -->
<div>{{{ userInput }}}</div>
<!-- SECURE: double-brace, auto-escaped -->
<div>{{ userInput }}</div>
JavaScript — DOM Sinks
// VULNERABLE: innerHTML with URL fragment
const name = location.hash.substring(1);
document.getElementById('greeting').innerHTML = 'Hello, ' + name;
// SECURE: textContent
const name = location.hash.substring(1);
document.getElementById('greeting').textContent = 'Hello, ' + name;
// VULNERABLE: eval with postMessage data
window.addEventListener('message', (event) => {
eval(event.data);
});
// SECURE: parse and validate; never eval postMessage data
window.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
// handle data safely
});
React
// VULNERABLE: dangerouslySetInnerHTML with user input
function Comment({ content }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
// SECURE: render as text (auto-escaped by React)
function Comment({ content }) {
return <div>{content}</div>;
}
Angular
// VULNERABLE: bypassing Angular's DomSanitizer
constructor(private sanitizer: DomSanitizer) {}
getUserHtml(input: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(input); // unsafe if input is user-controlled
}
<!-- VULNERABLE: [innerHTML] with unsanitized value -->
<div [innerHTML]="userInput"></div>
<!-- SECURE: use interpolation (auto-escaped) -->
<div>{{ userInput }}</div>
Ruby on Rails
<%# VULNERABLE: raw() or html_safe with user input %>
<%= raw(@user.bio) %>
<%= @user.bio.html_safe %>
<%# SECURE: default ERB escaping %>
<%= @user.bio %>
Java — JSP
<%-- VULNERABLE: scriptlet echo --%>
<p>Hello, <%= request.getParameter("name") %></p>
<%-- VULNERABLE: EL without c:out --%>
<p>Hello, ${param.name}</p>
<%-- SECURE: c:out escaping --%>
<p>Hello, <c:out value="${param.name}"/></p>
Go — html/template vs. text/template
// VULNERABLE: using text/template (no HTML escaping)
import "text/template"
tmpl := template.Must(template.New("").Parse("<h1>Hello, {{.Name}}!</h1>"))
tmpl.Execute(w, data)
// VULNERABLE: using template.HTML() cast to bypass escaping
import "html/template"
name := template.HTML(r.URL.Query().Get("name")) // bypasses auto-escaping
// SECURE: html/template with plain string value
import "html/template"
tmpl := template.Must(template.New("").Parse("<h1>Hello, {{.Name}}!</h1>"))
tmpl.Execute(w, data) // .Name is a plain string — auto-escaped
Execution
This skill runs in three phases using subagents. Pass the contents of sast/architecture.md to all subagents as context.
Phase 1: Find XSS Sink Sites
Launch a subagent with the following instructions:
Goal: Find every location in the codebase where data is rendered into HTML, JavaScript, or the DOM in a way that could allow script injection —
Truncated for display — read the full file on GitHub.
Related Skills
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
pptx
177.9kUse this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an em…
design
130.2kComprehensive design skill: brand identity, design tokens, UI styling, logo generation (55 styles, Gemini, Atlas Cloud, or MuAPI AI), corporate identity program (50 deliverables, CIP mockups), HTML presentations (Chart.js), banner design (22 styles, social/ads/web/print), icon design (15 styles, SVG…
ui-ux-pro-max
130.2kUI/UX design intelligence for web, mobile, and desktop. This skill should be used when designing, building, reviewing, or fixing interfaces, including pages, components, design systems, accessibility, interaction, responsive layout, typography, color, charts, and stack-specific UI implementation.
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
