AkurAI Build
Menu

AkurAI-Build

public

Latest change 1c2159692a31765cd66ed709791ba11468054873 - Initial commit: bunfork v0.1.0 source tree by Olafur Bui

{% extends "docs.html" %}
{% block title %}Security model ยท Bunfork docs{% endblock %}
{% block description %}Understand Bunfork's secret handling, artifact verification, origin controls, security headers, network boundary, and deliberate limitations.{% endblock %}
{% block breadcrumb %}Security{% endblock %}
{% block docs_title %}Security model{% endblock %}
{% block docs_summary %}Bunfork reduces the runtime and fails closed at file, schema, route, and input boundaries. It cannot replace host isolation, TLS, identity, or operational discipline.{% endblock %}
{% block docs_content %}
<section class="doc-section" aria-labelledby="production-checklist">
  <h2 id="production-checklist">Production checklist</h2>
  <ul class="security-checklist">
    <li><strong>Firewall port 3100.</strong><span>The default <code>0.0.0.0:3100</code> listener is intentionally LAN-visible.</span></li>
    <li><strong>Terminate TLS at a trusted reverse proxy.</strong><span>Bunfork has no built-in TLS and should not face the public internet directly.</span></li>
    <li><strong>Set the public HTTPS origin.</strong><span>Use <code>BUNFORK_PUBLIC_ORIGIN=https://app.example.com</code> so browser mutations must match it.</span></li>
    <li><strong>Separate the database key and API token.</strong><span>Generate each independently and keep both readable only by the service account.</span></li>
    <li><strong>Keep state outside releases.</strong><span>Never place keys, tokens, databases, or backups under <code>app/pages</code>, <code>public</code>, or the deployment directory.</span></li>
    <li><strong>Back up the key separately.</strong><span>Database backups remain encrypted with the live database key.</span></li>
    <li><strong>Stop writers before restore.</strong><span>Restore is a verified offline operation, not a distributed transaction.</span></li>
  </ul>
</section>

<section class="doc-section" aria-labelledby="secret-handling">
  <h2 id="secret-handling">Secret handling</h2>
  <ul class="check-list">
    <li><code>keygen</code> creates a 256-bit random value in a private file.</li>
    <li>Secret files must not be accessible by group or others.</li>
    <li>File values take precedence over environment values.</li>
    <li>Decoded secret comparisons are constant-time, including the key/token inequality check.</li>
    <li>The explicit frontend build environment excludes <code>BUNFORK_DB_KEY</code> and <code>BUNFORK_API_TOKEN</code>.</li>
    <li>Page trees reject hidden entries, links, and special files; public assets reject sensitive paths; deploy inventory rejects recognized secret patterns.</li>
  </ul>
</section>

<section class="doc-section" aria-labelledby="request-boundary">
  <h2 id="request-boundary">Request boundary</h2>
  <div class="table-wrap">
    <table>
      <thead><tr><th>Surface</th><th>Control</th></tr></thead>
      <tbody>
        <tr><td>Vector API</td><td>Bearer authentication; constant-time token comparison</td></tr>
        <tr><td>Browser mutations</td><td>Origin must equal the configured public origin or current host</td></tr>
        <tr><td>Request bodies</td><td>1 MiB cap plus vector-specific validation and work budgets</td></tr>
        <tr><td>Native pages</td><td>Auto-escaped template values and bounded multi-value query parsing</td></tr>
        <tr><td>Hidden request paths</td><td>Rejected before routing</td></tr>
        <tr><td>Health/readiness</td><td>Public and GET-only by design</td></tr>
      </tbody>
    </table>
  </div>
</section>

<section class="doc-section" aria-labelledby="response-headers">
  <h2 id="response-headers">Response headers</h2>
  <p>Native responses set a self-only content security policy, deny framing, disable MIME sniffing, use a no-referrer policy, and disable camera, geolocation, and microphone access.</p>
  <p>Static exports need same-origin browser code and may contain framework bootstrap inline scripts or styles. Bunfork's static policy permits those official export patterns. For a narrower policy, configure build-specific hashes or nonces at the trusted reverse proxy.</p>
</section>

<section class="doc-section" aria-labelledby="file-boundary">
  <h2 id="file-boundary">File and artifact boundary</h2>
  <p>Native routes, templates, and public assets reject hidden entries, links, hard links, special files, ambiguous routes, and unsafe paths. Production compiles routes and preloads assets before binding.</p>
  <p>Static admission additionally records every byte length and digest in a strict manifest. Verification happens offline with <code>doctor</code> and again before the static server binds.</p>
</section>

<aside class="doc-callout warning" aria-labelledby="not-protected">
  <h2 id="not-protected">What encryption cannot protect</h2>
  <p>A compromised live process, service account, root user, TLS proxy, binary, or unlocked key can access plaintext. Bunfork also has no user accounts, roles, remote backup transport, distributed locks, Windows hardening guarantee, or defense against hostile same-UID filesystem races. Isolate untrusted code under another OS account or container.</p>
</aside>

<section class="doc-section" aria-labelledby="static-scope">
  <h2 id="static-scope">The smallest security surface</h2>
  <p>If an application only needs compiled browser files, use static mode. It does not open the database or require a key, token, tenant, model, migration, native template engine, or foreign server runtime.</p>
  <pre><code>./target/release/bunfork doctor \
  --static frontend/out \
  --manifest bunfork-static.json

./target/release/bunfork serve \
  --static frontend/out \
  --manifest bunfork-static.json</code></pre>
</section>

<nav class="docs-pagination" aria-label="Documentation pagination">
  <a href="/docs/deployment"><small>Previous</small><span aria-hidden="true">โ†</span> Deploy &amp; recover</a>
  <a href="/docs"><small>Back to start</small>Documentation overview <span aria-hidden="true">โ†—</span></a>
</nav>
{% endblock %}