Client-side security analysis (DOM XSS, React/Vue/Angular, SSR, prototype pollution)
From perseusnpx claudepluginhub kaivyy/perseus --plugin perseusThis skill uses the workspace's default tool permissions.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
IMPORTANT: This skill performs client-side security analysis on the user's own codebase. This is defensive security testing to find browser-side vulnerabilities.
Authorization: The user owns this codebase and has explicitly requested this specialized analysis.
| Framework | Versions | Special Considerations |
|---|---|---|
| React | 16+, 18+, 19+ | RSC, Server Actions, JSX injection |
| Next.js | 12+, 13+, 14+, 15+ | App Router, Server Components, Middleware |
| Vue | 2, 3 | v-html, template injection |
| Angular | 12+ | bypassSecurityTrust*, template injection |
| Svelte | 3, 4, 5 | {@html}, SSR |
| SolidJS | 1.x | innerHTML, SSR |
| Vanilla JS | ES6+ | Direct DOM manipulation |
| jQuery | All | .html(), .append() |
This specialist skill performs deep client-side JavaScript security analysis, focusing on vulnerabilities in modern frameworks including React, Vue, Angular, and SSR frameworks.
When to Use: After /scan identifies significant client-side JavaScript, SPAs, or SSR applications.
Goal: Find DOM-based XSS, prototype pollution, and framework-specific vulnerabilities.
| Mode | Specialist Behavior |
|---|---|
PRODUCTION_SAFE | Code-level and rendering-path analysis, minimal runtime probes |
STAGING_ACTIVE | Controlled browser-side verification with throttling |
LAB_FULL | Expanded dynamic client attack-surface validation |
LAB_RED_TEAM | End-to-end client attack-chain simulation in isolated lab |
deliverables/engagement_profile.md before active runtime testing.PRODUCTION_SAFE when mode is not specified.| Risk | Description | Impact |
|---|---|---|
| DOM XSS | Client-side script injection | Account takeover, data theft |
| React XSS | Unsafe HTML rendering, href injection | XSS via JSX |
| SSR Injection | Server component injection | RCE, data leak |
| Prototype Pollution | Object prototype manipulation | XSS, DoS, logic bypass |
| PostMessage Abuse | Cross-origin message issues | Data leakage, XSS |
| DOM Clobbering | HTML overwriting JS variables | XSS, security bypass |
| Client Storage | Sensitive data exposure | Session hijacking |
deliverables/engagement_profile.md.deliverables/verification_scope.md when present.PRODUCTION_SAFE, prefer static and minimal observable checks only.React XSS Analyst:
Vulnerable Patterns:
// VULNERABLE - Dangerous HTML rendering
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// VULNERABLE - javascript: in href
<a href={userUrl}>Click</a>
// Attack: userUrl = "javascript:alert(1)"
// VULNERABLE - Dynamic component
const Component = components[userInput];
return <Component />;
// VULNERABLE - Spread props from user
<div {...userProps} />
// Attack: userProps = { dangerouslySetInnerHTML: { __html: '<script>...' } }
Next.js Server Component Analyst:
Patterns:
// VULNERABLE - SQL in Server Component
async function UserPage({ params }) {
const user = await db.query(`SELECT * FROM users WHERE id = ${params.id}`);
return <div>{user.name}</div>;
}
// VULNERABLE - Exposing secrets to client
// In Server Component that passes to Client Component
<ClientComponent apiKey={process.env.SECRET_KEY} />
// VULNERABLE - Unvalidated redirect
import { redirect } from 'next/navigation';
redirect(userInput);
Next.js Server Actions Analyst:
Patterns:
// VULNERABLE - No auth check in Server Action
'use server'
async function deleteUser(userId: string) {
await db.users.delete(userId); // No auth check!
}
// VULNERABLE - SQL injection in Server Action
'use server'
async function searchUsers(query: string) {
return db.query(`SELECT * FROM users WHERE name LIKE '%${query}%'`);
}
// VULNERABLE - CSRF (if custom implementation)
// Server Actions have built-in CSRF protection, but check custom forms
Next.js Middleware Analyst:
Patterns:
// VULNERABLE - Open redirect
export function middleware(request: NextRequest) {
const url = request.nextUrl.searchParams.get('redirect');
return NextResponse.redirect(url); // No validation!
}
// VULNERABLE - Auth bypass via header manipulation
export function middleware(request: NextRequest) {
if (request.headers.get('x-admin') === 'true') {
return NextResponse.next(); // Spoofable!
}
}
React State Exposure Analyst:
Patterns:
// VULNERABLE - Secrets in client state
const [config, setConfig] = useState({
apiKey: 'sk-xxx', // Exposed in React DevTools
adminToken: '...'
});
// VULNERABLE - SSR hydration mismatch leaking data
// Server renders with user data, client sees different user's data
Vue XSS Analyst:
Patterns:
<!-- VULNERABLE - v-html with user input -->
<div v-html="userContent"></div>
<!-- VULNERABLE - Dynamic component -->
<component :is="userComponent" />
<!-- VULNERABLE - Template compilation -->
<script>
new Vue({
template: userTemplate // If user controls this
});
</script>
<!-- VULNERABLE - javascript: in :href -->
<a :href="userUrl">Link</a>
Nuxt.js Analyst:
Patterns:
// VULNERABLE - Nuxt 3 server routes
export default defineEventHandler((event) => {
const id = getQuery(event).id;
return db.query(`SELECT * FROM items WHERE id = ${id}`);
});
// VULNERABLE - Exposing secrets
// nuxt.config.ts
runtimeConfig: {
public: {
secretKey: process.env.SECRET // Exposed to client!
}
}
Vue State Analyst:
Angular XSS Analyst:
Patterns:
// VULNERABLE - bypassSecurityTrust*
constructor(private sanitizer: DomSanitizer) {}
getHtml() {
return this.sanitizer.bypassSecurityTrustHtml(userInput);
}
// VULNERABLE - Template injection
@Component({
template: userTemplate // If user controls this
})
// VULNERABLE - innerHTML binding
<div [innerHTML]="userContent"></div>
Angular SSR Analyst:
Source Identification Agent:
Sources:
// URL-based sources
location.hash
location.search
location.href
document.URL
document.documentURI
document.referrer
// Storage sources
localStorage.getItem()
sessionStorage.getItem()
document.cookie
// Message sources
window.addEventListener('message', (e) => e.data)
// Framework-specific
// React: props from URL, useSearchParams()
// Next.js: searchParams, params
// Vue: $route.query, $route.params
Sink Identification Agent:
Sinks:
// Direct sinks
element.innerHTML = data
element.outerHTML = data
document.write(data)
document.writeln(data)
// jQuery sinks
$(selector).html(data)
$(selector).append(data)
$(data) // If data contains HTML
// Eval sinks
eval(data)
new Function(data)
setTimeout(data, 0)
setInterval(data, 0)
// Location sinks
location.href = data
location.assign(data)
location.replace(data)
window.open(data)
// Framework-specific already covered above
Flow Tracer Agent:
URL Scheme Analyst:
Patterns:
// React
<a href={url}> // If url = "javascript:..."
<iframe src={url}>
// Check validation:
if (!url.startsWith('https://')) { /* reject */ }
Pollution Source Analyst:
Patterns:
// VULNERABLE - Deep merge without __proto__ check
function merge(target, source) {
for (let key in source) {
if (typeof source[key] === 'object') {
target[key] = merge(target[key] || {}, source[key]);
} else {
target[key] = source[key]; // Can set __proto__
}
}
}
// VULNERABLE - URL params to object
const params = Object.fromEntries(new URLSearchParams(location.search));
// Attack: ?__proto__[isAdmin]=true
// VULNERABLE libraries (check versions)
// lodash < 4.17.12
// jQuery < 3.4.0
// minimist < 1.2.3
Gadget Finder Agent:
Patterns:
// GADGET - Property access on polluted prototype
if (options.isAdmin) { // Can be polluted
showAdminPanel();
}
// GADGET - HTML attribute setting
element.setAttribute(key, config[key]); // key from polluted proto
Library Analyst:
PostMessage Receiver Analyst:
Patterns:
// VULNERABLE - No origin check
window.addEventListener('message', (e) => {
eval(e.data.code); // RCE via any origin
});
// VULNERABLE - Weak origin check
window.addEventListener('message', (e) => {
if (e.origin.includes('trusted.com')) { // trusted.com.evil.com bypasses
// ...
}
});
// SAFE
window.addEventListener('message', (e) => {
if (e.origin !== 'https://trusted.com') return;
// ...
});
PostMessage Sender Analyst:
Patterns:
// VULNERABLE - Sending to any origin
parent.postMessage(sensitiveData, '*');
// VULNERABLE - Token in message
iframe.contentWindow.postMessage({ token: authToken }, '*');
Storage Security Analyst:
Issues:
// VULNERABLE - Token in localStorage (XSS accessible)
localStorage.setItem('authToken', token);
// VULNERABLE - Sensitive data persisted
localStorage.setItem('user', JSON.stringify({
ssn: '123-45-6789',
creditCard: '4111...'
}));
Client Secret Analyst:
Patterns:
// Secrets in JS bundles
const API_KEY = 'sk-xxx';
const STRIPE_SECRET = 'sk_live_xxx';
// Check .env files exposed
// Check webpack/vite config for DefinePlugin exposure
| Attack | Safe Test Payload | Verification |
|---|---|---|
| DOM XSS | #<img src=x onerror=alert(1)> | Alert box appears |
| React href | javascript:alert(1) | Alert on click |
| Prototype Pollution | ?__proto__[test]=polluted | ({}).test === 'polluted' |
| PostMessage | Send from different origin | Check if processed |
Create deliverables/client_side_analysis.md:
# Client-Side Security Analysis
## Summary
| Category | Issues Found | Critical | High | Medium |
|----------|--------------|----------|------|--------|
| React/Next.js XSS | X | Y | Z | W |
| Vue XSS | X | Y | Z | W |
| Angular XSS | X | Y | Z | W |
| DOM XSS | X | Y | Z | W |
| Server Components | X | Y | Z | W |
| Prototype Pollution | X | Y | Z | W |
| PostMessage | X | Y | Z | W |
| Client Storage | X | Y | Z | W |
## Framework Detected
- Primary: [React 18, Next.js 14, Vue 3, etc.]
- SSR: [Yes/No]
- Build Tool: [Vite, Webpack, Turbopack]
## Critical Findings
### [CLIENT-001] XSS via dangerouslySetInnerHTML
**Severity:** Critical
**Framework:** React
**Location:** `components/Comment.tsx:23`
**Vulnerable Code:**
```jsx
<div dangerouslySetInnerHTML={{ __html: comment.body }} />
Attack:
comment.body = "<img src=x onerror=alert(document.cookie)>"
Impact: Full XSS - can steal cookies, perform actions as user
Remediation:
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(comment.body) }} />
Severity: Critical
Framework: Next.js 14
Location: app/actions/search.ts:12
Vulnerable Code:
'use server'
async function searchProducts(query: string) {
return db.query(`SELECT * FROM products WHERE name LIKE '%${query}%'`);
}
Severity: High
Location: middleware.ts:8
| Framework | Auto-Escape | Common Pitfalls |
|---|---|---|
| React | Yes (JSX) | dangerouslySetInnerHTML, href |
| Next.js | Yes | Server Actions auth, middleware |
| Vue | Yes | v-html, :href |
| Angular | Yes | bypassSecurityTrust* |
**Next Step:** DOM XSS findings can be verified with browser testing.