# Security

> Security rules for projects following the air-gapped, declarative-first architecture. Covers Content Security Policy, recommended security headers, and the architectural decisions that enable a strict CSP without unsafe-inline or unsafe-eval. Use when configuring deployment, reviewing CSP, or auditing for inline-script or inline-style violations.

- Skill: `autocss-com/security` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add autocss-com/security`
- Raw SKILL.md: https://api.skillmd.com/api/skills/autocss-com/security/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- License: MIT
- Author: Autocss-com (https://skillmd.com/u/autocss-com)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/autocss-com/security

---


# Security

The architecture's separation of concerns enables a strict Content Security Policy without any `unsafe-*` exceptions. This skill defines the headers, the CSP, and the architectural decisions that make them possible.

## Why the architecture is secure by construction

- **No inline JavaScript.** No `<script>` with inline JS. No `on*=` event-handler attributes. CSP can ban inline scripts entirely.
- **No inline CSS.** No `<style>` tags. No `style=` attributes. CSP can ban inline styles entirely.
- **No third-party runtime dependencies.** No CDN loads. CSP `script-src 'self'` and `style-src 'self'` cover everything.
- **No `eval`, no `Function` constructor, no dynamic code generation.** CSP can ban these via the absence of `unsafe-eval`.
- **No HTML injection.** JavaScript injects text content and creates elements via `createElement`, never via `innerHTML` with markup strings.

These come from the `html`, `css`, and `javascript` skills as positive whitelists. The security posture is a consequence, not a separate effort.

## Recommended security headers

These are the only headers required for a hardened deployment.

```
Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self';
  img-src 'self' data:;
  font-src 'self';
  connect-src 'self' https://api.example.tld;
  object-src 'none';
  base-uri 'self';
  frame-ancestors 'none';
  upgrade-insecure-requests;
  form-action 'self';

Permissions-Policy:
  accelerometer=(), autoplay=(), camera=(), clipboard-read=(),
  clipboard-write=(), geolocation=(), gyroscope=(), magnetometer=(),
  microphone=(), payment=(), usb=()

Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-site
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```

`connect-src` is the only directive that needs project-specific tuning — replace `https://api.example.tld` with the actual API origin declared once in `api.js`.

## CSP-compatible patterns

These patterns are what the architecture already produces. They are listed here as the verifiable signal that the code is secure-by-construction.

**HTML** — no inline event handlers, no `style` attribute:

```html
<label role="button" aria-label="Save">
  Save
  <input type="checkbox" aria-hidden="true" />
</label>
```

**CSS** — controls all UI state via selectors on data presence:

```css
article:has(> ul:not(:empty)) {
  /* show populated state */
}
```

**JavaScript** — fetches data, throws on error, no UI logic:

```javascript
export async function fetchJSON(url, opts = {}) {
  const res = await fetch(url, {
    ...opts,
    headers: { 'Accept': 'application/json' }
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}
```

## Threat model — what we defend against

| Threat | Defense |
|---|---|
| XSS via inline scripts | CSP `script-src 'self'`, no inline `<script>` blocks, no `on*=` attributes |
| XSS via injected HTML | JS uses `createElement` and `textContent`, never `innerHTML` with markup |
| Style injection | CSP `style-src 'self'`, no inline `<style>`, no `style=` attributes |
| Clickjacking | CSP `frame-ancestors 'none'` (unless intentionally embeddable) |
| Supply-chain compromise | No third-party runtime dependencies |
| Mixed content | `upgrade-insecure-requests`, HSTS |
| MIME sniffing | `X-Content-Type-Options: nosniff` |
| Referrer leakage | `Referrer-Policy: strict-origin-when-cross-origin` |
| Unintended permissions | `Permissions-Policy` denies everything by default |

## Secrets

- Never commit secrets, tokens, API keys, or `.env` files.
- The front-end never embeds private credentials. Use server-side proxies. If a public token is unavoidable, it must be scoped and revocable.
- `.gitignore` already excludes `.env`.

## Content sanitization

External data is treated as untrusted. The architecture handles this by:

- Using `textContent` (not `innerHTML`) when injecting strings into the DOM
- Using `setAttribute` with a known allowlist when setting attributes from data
- Refusing to render any data field that contains markup characters in a way that would invoke parsing

If a use case genuinely requires rendering trusted HTML, that is documented as an exception with the allowlist of permitted elements at the integration boundary.

## Supply chain

- Enable GitHub Dependabot alerts.
- Enable secret scanning.
- Enable CodeQL for JavaScript.
- Verify checksums or SLSA provenance for any downloaded build tools.
- CI fails on:
  - Known vulnerabilities above defined severity threshold
  - Presence of secrets or high-entropy strings
  - Inline scripts, inline styles, or `on*=` handlers in HTML

## What security never does in this architecture

- Never relies on `unsafe-inline` to make things work
- Never relies on `unsafe-eval`
- Never adds CSP exceptions for third-party CDNs (no third-party assets are loaded)
- Never trusts data origin without sanitization at the integration boundary
- Never embeds secrets in front-end code

## Baseline & support

_Checked against MDN as of 2026-07-16._

- `Content-Security-Policy` — **Baseline Widely available** (\* some directives vary) — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
- `Strict-Transport-Security` (HSTS) — **Baseline Widely available** — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security
- `Referrer-Policy` — **Baseline Widely available** — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy
- `Permissions-Policy` — **Limited availability** (MDN also marks it Experimental; unsupported in Firefox and Safari) — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Permissions-Policy
- `Cross-Origin-Opener-Policy` / `Cross-Origin-Embedder-Policy` / `Cross-Origin-Resource-Policy` — **MDN assigns no Baseline tier**; cross-browser per BCD (COOP/COEP in Chrome, Edge, Firefox and Safari 15.2+) — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy
- `X-Content-Type-Options: nosniff` — **MDN assigns no Baseline tier**; universally supported — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options

**Canonical rules:** https://github.com/Autocss-com/ai/blob/main/AGENTS.md

## References

- `references/csp.md` — full CSP with rationale per directive
- `references/headers.md` — every recommended header with explanation
- `references/threat-model.md` — full threat model, defenses, residual risks
- `references/sanitization.md` — text vs. HTML injection rules
- W3C CSP Level 3: https://www.w3.org/TR/CSP3/
- MDN CSP: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
- OWASP Secure Headers: https://owasp.org/www-project-secure-headers/

