diff --git a/README.md b/README.md index 6c3a5f7..9835a07 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,23 @@ content/ Full documentation at [sukr.io](https://sukr.io) (built with sukr). +## Security + +sukr processes content at **build time only** — there is no runtime attack surface. + +**Trust Model:** + +- **Untrusted:** Markdown content, frontmatter, third-party templates +- **Trusted:** The compiled sukr binary, Tree-sitter grammars + +**Security Implications:** + +- Raw HTML in Markdown is passed through (CommonMark spec). If your content comes from untrusted sources, review it before building. +- URLs in links and images are escaped to prevent attribute injection. +- Templates use Tera's auto-escaping for variables; `{{ content | safe }}` is used intentionally for pre-rendered HTML. + +For deployment-time security (CSP headers, etc.), see the [Security docs](https://sukr.io/security.html). + ## License MIT diff --git a/docs/content/security.md b/docs/content/security.md new file mode 100644 index 0000000..040eed5 --- /dev/null +++ b/docs/content/security.md @@ -0,0 +1,101 @@ +--- +title: Security +description: Content trust model and deployment security guidance +weight: 90 +--- + +# Security + +sukr is a **build-time only** compiler with no runtime attack surface. Security considerations focus on content processing and deployment. + +## Trust Model + +| Source | Trust Level | Rationale | +| :------------------- | :--------------- | :--------------------------------------------------- | +| Markdown content | **Untrusted** | May come from contributors, CMS, or external sources | +| YAML frontmatter | **Untrusted** | Parsed from content files | +| Templates | **Semi-trusted** | User-controlled but typically from known sources | +| sukr binary | **Trusted** | Compiled from audited Rust code | +| Tree-sitter grammars | **Trusted** | Compiled into the binary | + +## Content Processing + +### HTML Passthrough + +Per the CommonMark specification, raw HTML in Markdown is passed through to output: + +```markdown + +``` + +**If your content comes from untrusted sources**, review it before building. sukr does not sanitize HTML — this is intentional to preserve legitimate use cases. + +### URL Escaping + +Link and image URLs are escaped to prevent attribute injection attacks: + +```markdown + + +[click me](<"%3E%3Cscript%3Ealert(1)%3C/script%3E>) +``` + +Produces escaped output, not executable script. + +### Template Auto-Escaping + +Tera templates auto-escape variables by default: + +- `{{ title }}` — escaped (safe) +- `{{ page.description }}` — escaped (safe) +- `{{ content | safe }}` — intentionally unescaped (pre-rendered HTML) + +## Deployment Security + +### Content Security Policy + +For maximum protection when serving sukr-generated sites, configure CSP headers on your web server or CDN. + +**Recommended policy for sukr sites:** + +``` +Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'none'; frame-ancestors 'none' +``` + +This policy: + +- ✅ Allows styles (including inline for syntax highlighting) +- ✅ Allows images and data URIs (for Mermaid SVGs) +- ✅ Blocks all JavaScript execution +- ✅ Prevents clickjacking + +### Platform-Specific Headers + +**Cloudflare Pages** (`public/_headers`): + +``` +/* + Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'none' + X-Content-Type-Options: nosniff + X-Frame-Options: DENY +``` + +**Netlify** (`public/_headers`): + +``` +/* + Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'none' + X-Content-Type-Options: nosniff +``` + +**Nginx**: + +```nginx +add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'none'"; +add_header X-Content-Type-Options nosniff; +add_header X-Frame-Options DENY; +``` + +## Reporting Issues + +Report security issues via [security@sukr.io](mailto:security@sukr.io) or GitHub Security Advisories.