Source profileQuality 91/100

event4u-app/agent-config/src/skills/frontend-render-security/SKILL.md

frontend-render-security

Writing/reviewing client-side UI (React/Vue/vanilla) — insecure-render + client-trust gaps AI ships: XSS via innerHTML, client secrets, client-only auth, CORS wildcard, token in localStorage

Source repository stars
9
Declared platforms
0
Static risk flags
0
Last source update
2026-08-28
Source checked
2026-08-28

Decision brief

What it does: where it fits

AI optimizes for the shortest code that produces the requested visible behavior and omits the invisible defensive layer — the sanitizer, the origin check, the server-side gate, the security header. Large samples put XSS in a majority of AI frontend code and 2.74× more XSS than h…

Best for

  • Writing or modifying a component, template, or client-side script that renders data, calls an API, handles auth, or reads the URL / postMessage.
  • Reviewing an AI-authored frontend diff.
  • Editing .tsx / .jsx / .vue / .svelte / .html or client-side .js / .ts.

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/frontend-render-security"
Safe inspection promptEditorial

Inspect the Agent Skill "frontend-render-security" from https://github.com/event4u-app/agent-config/blob/6a5670b7881a676c0da90d2afb950298087c4ccb/src/skills/frontend-render-security/SKILL.md at commit 6a5670b7881a676c0da90d2afb950298087c4ccb. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    Procedure

    1. Identify the sinks in the diff: HTML/JS render points, API calls, auth/role checks, URL / postMessage reads, secret/token usage. 2. Run the backstop greps below; for each hit, apply the matching fix from the patterns table. 3. For every client-side gate, confirm a server-side…

    Identify the sinks in the diff: HTML/JS render points, API calls, auth/role checks, URL / postMessage reads, secret/token usage.Run the backstop greps below; for each hit, apply the matching fix from the patterns table.For every client-side gate, confirm a server-side twin exists (the client is never the security boundary).
  2. 02

    When to use

    Do NOT use when: the change is server-only, CLI, or non-UI — route to security / security-sensitive-stop.

    Writing or modifying a component, template, or client-side script that renders data, calls an API, handles auth, or reads the URL / postMessage.Reviewing an AI-authored frontend diff.Editing .tsx / .jsx / .vue / .svelte / .html or client-side .js / .ts.
  3. 03

    The Iron Law

    Review the “The Iron Law” section in the pinned source before continuing.

    Review and apply the “The Iron Law” source section.
  4. 04

    The patterns AI ships by default

    Review the “The patterns AI ships by default” section in the pinned source before continuing.

    Review and apply the “The patterns AI ships by default” source section.
  5. 05

    The server-composed bootstrap payload

    A payload assembled server-side and serialised into the page for a client island is a data-exposure surface: whatever is put in it is readable by anyone who can load the page — no API call, no auth check, view-source. Several mainstream frameworks ship their own named channel fo…

    A payload assembled server-side and serialised into the page for a client island is a data-exposure surface: whatever is put in it is readable by anyone who can load the page — no API call, no auth check, view-source. S…Inspect the existing payload before judging any field. Read what the channel already carries and check current call sites for what the client actually consumes — a field is only defensible against what the page needs, a…The per-field question, which is what this section is:

Permission review

Static risk signals and limitations

No configured static risk pattern was detected

This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score91/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars9SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
event4u-app/agent-config
Skill path
src/skills/frontend-render-security/SKILL.md
Commit
6a5670b7881a676c0da90d2afb950298087c4ccb
License
MIT
Collected
2026-08-28
Default branch
main
View the original SKILL.md

frontend-render-security

AI optimizes for the shortest code that produces the requested visible behavior and omits the invisible defensive layer — the sanitizer, the origin check, the server-side gate, the security header. Large samples put XSS in a majority of AI frontend code and ~2.74× more XSS than human code; every agent in the Tenzai benchmark shipped client-side flaws. These are high-precision, grep-catchable patterns — stop them at authoring time.

When to use

  • Writing or modifying a component, template, or client-side script that renders data, calls an API, handles auth, or reads the URL / postMessage.
  • Reviewing an AI-authored frontend diff.
  • Editing .tsx / .jsx / .vue / .svelte / .html or client-side .js / .ts.

Do NOT use when: the change is server-only, CLI, or non-UI — route to security / security-sensitive-stop.

The Iron Law

NEVER RENDER NON-CONSTANT INPUT INTO AN HTML/JS SINK WITHOUT ENCODING OR SANITIZING.
THE CLIENT IS UNTRUSTED — EVERY CLIENT GATE NEEDS A SERVER-SIDE TWIN.
NO SECRET, PRIVILEGED KEY, OR SESSION TOKEN LIVES IN CLIENT CODE OR localStorage.

Procedure

  1. Identify the sinks in the diff: HTML/JS render points, API calls, auth/role checks, URL / postMessage reads, secret/token usage.
  2. Run the backstop greps below; for each hit, apply the matching fix from the patterns table.
  3. For every client-side gate, confirm a server-side twin exists (the client is never the security boundary).
  4. Emit the per-diff verdict (Output format); surface any unresolved hit to the user.

The patterns AI ships by default

PatternWhy it's dangerousDo instead
dangerouslySetInnerHTML / v-html / .innerHTML = on non-constant valueStored/DOM XSS (CWE-79)render as text, or sanitize (DOMPurify) if HTML is required
Secret / API key inline or in NEXT_PUBLIC_* / VITE_*Bundler inlines it into shipped JS (CWE-798)call the third party via a backend-for-frontend proxy; only truly-public values get a public prefix
Client-side-only auth / role / validationBypassable with dev tools or a proxy (CWE-602)client gate is UX only; enforce the same check server-side
location.* / query param → HTML or JS sinkDOM XSS (CWE-79)textContent; never pass URL data into an HTML/exec sink
CORS origin: '*' (esp. with credentials)Any site reads authenticated responses (CWE-942)explicit origin allow-list; never reflect Origin on credentialed routes
Token / JWT in localStorage / sessionStorageXSS-exfiltratable (CWE-522)HttpOnly; Secure; SameSite cookie
addEventListener('message', …) without event.origin checkAny embedder drives the handler (CWE-346)strict-equality check event.origin against an allow-list first
redirect / next param → location / router.pushOpen redirect / phishing (CWE-601)relative-path or allow-listed-host only; reject external / non-http schemes
eval / new Function / string-setTimeout on inputEval injection / RCE (CWE-95)a parser or explicit allow-list
target="_blank" without rel="noopener"Reverse tabnabbing (CWE-1022)add rel="noopener noreferrer"
Missing CSP; missing alt/label/contrastNo XSS second line of defense; a11y failuresstrict CSP (no unsafe-inline); alt text, labels, AA contrast

The server-composed bootstrap payload

A payload assembled server-side and serialised into the page for a client island is a data-exposure surface: whatever is put in it is readable by anyone who can load the page — no API call, no auth check, view-source. Several mainstream frameworks ship their own named channel for exactly this, so the pattern is a documented mechanism rather than one project's arrangement.

Inspect the existing payload before judging any field. Read what the channel already carries and check current call sites for what the client actually consumes — a field is only defensible against what the page needs, and a review that never opened the payload is a guess. The grep below finds it.

The per-field question, which is what this section is:

Would I return this field from a public, unauthenticated endpoint? If not, it does not belong in the payload.

Field classes that recur and are almost always wrong there: internal ids that enumerate other users' rows · permission and role structures the client only needs a boolean of · feature-flag payloads carrying unreleased product names · anything from an admin-scoped query that was convenient to reuse · a whole serialised model where the page needs three of its fields.

Nothing enforces this, and the split is deliberate.

HalfWhat it doesWhat it cannot do
the grep belowlocates a payload a field was added totell a privileged field from a public one
this checklist entrycarries the judgementrun

The question is not decidable by any check: a grep over the framework-named payload channels cannot read intent. So the deterministic half is discovery, advisory and non-blocking, and its whole value is putting the question in front of a reader who would otherwise never see it. enforced_by: none is the honest field here — this section refuses nothing.

What may NOT be encoded. The particular channel any one repository uses. What is encoded is the question and the framework-named channels; a concrete in-house payload shape would be one repository's implementation shipped as guidance.

Backstop greps

Run before committing frontend changes; each should return zero (or every hit is read and justified):

# Insecure render + eval sinks
rg -n 'dangerouslySetInnerHTML|v-html|\.innerHTML\s*=|document\.write\(|\beval\(|new Function\('
# Client secrets / token storage
rg -n 'NEXT_PUBLIC_.*(SECRET|KEY|TOKEN|PASSWORD)|VITE_.*(SECRET|KEY)|localStorage\.setItem\([^)]*[Tt]oken'
# Wildcard CORS + unchecked postMessage + open redirect
rg -n "origin:\s*['\"]\*['\"]|Access-Control-Allow-Origin.*\*"
rg -n "addEventListener\(\s*['\"]message['\"]"   # then confirm each checks event.origin
# Unhardened external links
rg -n 'target=["'\'']_blank["'\'']'   # then confirm rel="noopener" present
# Server-composed bootstrap payload — LOCATES it; the per-field judgement is yours
rg -n '__NEXT_DATA__|__NUXT__|window\.__INITIAL_STATE__|@json\(|json_encode\([^)]*\)\s*\)?\s*</script>|dehydratedState'

Output format

  1. A per-diff verdict listing each pattern class checked and its result (clean / hit at file:line → fixed by <change>).
  2. The backstop greps run, with results.
  3. For any client gate added, the file:line of its server-side twin (or an explicit note that the server check already exists and where).

Gotcha

  • Modern browsers default _blank to noopener, but legacy/embedded webviews do not — keep the rel for portability.
  • NEXT_PUBLIC_/VITE_ on a genuinely public value (a publishable analytics ID) is fine; the violation is a sensitive name behind that prefix. Read the name, don't blanket-block the prefix.
  • A sanitizer (DOMPurify) is the fix only when HTML output is actually required; if plain text suffices, render text and skip the dependency.
  • Client-side validation is not wrong — it is wrong as the only enforcement. Keep it for UX; add the server twin.

Do NOT

  • Do NOT render user/DB HTML through dangerouslySetInnerHTML/v-html/innerHTML without a sanitizer.
  • Do NOT put a secret, privileged key, or session token in client code or web storage.
  • Do NOT treat a client-side role/auth check as a security boundary.
  • Do NOT set origin: '*' on a credentialed endpoint.
  • Do NOT auto-strip a grep hit without reading it — some innerHTML uses are on constant, trusted markup.

Auto-trigger keywords

  • frontend security
  • XSS
  • dangerouslySetInnerHTML
  • client-side secret
  • insecure render

See also

Frequently asked questions

What to verify before installation and use

What does the frontend-render-security source document cover?

AI optimizes for the shortest code that produces the requested visible behavior and omits the invisible defensive layer — the sanitizer, the origin check, the server-side gate, the security header. Large samples put XSS in a majority of AI frontend code and 2.74× more XSS than h…

How do I install frontend-render-security?

The source record exposes this install command: npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/frontend-render-security". Inspect the command and pinned source before running it.

Alternatives

Compare before choosing

Computed 1009

event4u-app/agent-config

existing-ui-audit

Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.

Computed 961,113

fcakyon/claude-codex-settings

vercel-react-view-transitions

Guide for implementing smooth, native-feeling animations using React's View Transition API (`<ViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions view

Computed 96224

yonatangross/orchestkit

json-render-catalog

json-render component catalog patterns for AI-safe generative UI. Define Zod-typed catalogs that constrain what AI can generate, use @json-render/shadcn for 36 pre-built components, optimize specs with YAML mode, and apply the three edit modes (patch/merge/diff) for progressive updates. Use when building AI-generated UIs, defining component catalogs, or integrating json-render into React/Vue/Svelte/React Native/Ink/Next.js projects.

Computed 96207

theBGuy/GitDesktop

vercel-react-view-transitions

Guide for implementing smooth, native-feeling animations using React's View Transition API (`<ViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions view