This document defines the practical security rules for beeui.
The goal is to improve UI/backend safety without creating unnecessary bureaucracy.
This is not a formal enterprise security program.
It is a lightweight engineering guide for deciding:
- what needs security attention;
- which checks are worth running;
- how to keep secrets, config, artifacts and UI/API responses safe;
- how to align security checks with the SDLC-light workflow.
Use this document together with:
docs/SDLC.mddocs/ROADMAP.mddocs/INTEGRATION.mddocs/API_CONTRACT.mddocs/WEB_UI.md
Security in beeui should follow these principles:
- read-only by default;
- protect secrets first;
- never expose product secrets through HTML/API/logs/artifacts;
- validate configuration explicitly;
- fail fast on invalid required inputs;
- treat product artifacts and adapter responses as untrusted input;
- keep UI useful but not overexposed;
- avoid hidden defaults for sensitive behavior;
- minimize attack surface;
- prefer simple designs over complex, fragile abstractions;
- keep product authority outside
beeui; - apply security checks proportionally to the change.
At minimum, beeui should protect:
- product secrets and environment references;
- session cookies and auth state;
- config values and config-change audit trails;
- artifact integrity and predictable artifact access;
- product runtime/source artifacts from unintended mutation;
- product adapter boundaries;
- HTML rendering safety;
- API response safety;
- dependency hygiene;
- file/path handling;
- parsing of external, product-provided or user-controlled input.
beeui must not become the authority source for product runtime behavior.
beeui must not own:
- trading decisions;
- broker calls;
- live execution;
- BeeAgent capability execution;
- product policy decisions;
- runtime guardrails;
- product config validation source of truth;
- product artifact semantics beyond display/read-model mapping.
Those responsibilities remain inside the product:
beecap;beeagent;- future Bee products.
Main rule:
BeeUI renders.
Product decides.
Changes in these areas should be treated more carefully:
config/start.pyconfig/*.ymlsrc/beeui_module/app.pysrc/beeui_module/server.pysrc/beeui_module/settings.pysrc/beeui_module/config.pysrc/beeui_module/api/*src/beeui_module/adapters/*src/beeui_module/artifacts/*src/beeui_module/auth/*src/beeui_module/config_ui/*src/beeui_module/actions/*src/beeui_module/core/security.pysrc/beeui_module/templates/*src/beeui_module/static/*- dependency files:
pyproject.tomluv.lock
beeui must not invent product state.
If data is unavailable, partial or corrupted, beeui should show:
empty;partial;degraded;unavailable;- explicit warning or reason.
It must not silently fabricate:
- profit;
- execution status;
- account state;
- approval status;
- runtime state;
- artifact content.
All routes and adapters are read-only by default.
Write/control behavior is allowed only when all are true:
- the route is explicitly designed as a bounded action;
- the product adapter exposes an explicit callback/API for it;
- validation is performed before execution;
- the action is audited;
- the user/session has the required role if auth is enabled;
- no broker/live/runtime authority is introduced implicitly.
Not allowed:
- hidden runtime mutation from dashboard routes;
- implicit config writes from preview routes;
- direct broker/order calls from
beeui; - arbitrary filesystem writes;
- automatic runtime restart/reload after config apply unless explicitly implemented, validated and documented.
Required beeui behavior must be controlled by config, not hidden code defaults.
If a new required key is introduced:
- it must be explicitly present in the relevant config example;
- it must be validated by
beeuiconfig loading; - the app must fail fast with a clear error if it is missing or invalid;
- docs must be updated if the contract changed.
Product-specific config validation remains the product's responsibility.
beeui may call product validation callbacks, but must not replace them.
Secrets must never appear in:
- HTML responses;
- JSON API responses;
- logs;
- storage artifacts;
- audit artifacts;
- test snapshots;
- PR screenshots;
- example payloads committed to repo.
Safe practice:
-
never dump full config blindly;
-
never dump full env;
-
redact keys containing:
secrettokenpasswordapi_keyapi_secretauthorizationcookiesessioncredential
-
never serialize raw secrets into JSON/JSONL;
-
never expose sensitive request headers.
Starting from Iteration 13.9:
beeui_langcookie is a user-preference cache, not a config source of truth.- Cookie value is validated against
app.locale.availablebefore setting and reading. - Invalid locale values are rejected — no cookie is set for invalid values.
samesite="lax"prevents CSRF-style locale manipulation from external sites.- Cookie path matches the configured
route_prefix. - Locale does not affect auth decisions, RBAC, or product behavior.
localStoragetheme keybeeui-themeis validated against allowlist (light,dark,system).- Invalid stored theme falls back to system default.
- Browser state (
localStorage, cookie) is not a product/config source of truth. - Locale resolution is valid query → valid cookie → configured default.
- Rejected chart render promises render a bounded localized error state without logging raw adapter payloads.
Logs should be:
- understandable;
- in English;
- sufficient for debugging;
- free from secret values.
Allowed:
- high-level runtime events;
- route startup events;
- adapter names;
- reason codes;
- safe artifact identifiers;
- non-sensitive config choices;
- state transitions.
Not allowed:
- raw secret values;
- full environment dumps;
- full request/response dumps with credentials;
- full cookies;
- session signing secrets;
- sensitive headers;
- unredacted product config.
beeui should avoid creating artifacts unless they are needed for:
- config change audit;
- operator action audit;
- support diagnostics;
- reproducible UI/backend behavior.
Artifacts should be:
- predictable;
- useful for debugging;
- consistent with logs;
- free from secrets.
If a new artifact is introduced, ask:
- does it help reproduce UI/admin/action behavior?
- does it expose anything sensitive?
- does it duplicate product source of truth?
- does it need redaction or omission?
- is it clearly marked as UI/support/audit artifact, not runtime truth?
Treat as untrusted:
- CLI args;
- config values;
- product adapter responses;
- HTTP responses from product APIs;
- file contents loaded from disk;
- restored JSON artifacts;
- JSONL rows;
- query parameters;
- form payloads;
- uploaded/static files if such support is added later.
Validate before use where reasonable.
Do not trust product artifacts just because they were created locally. Local artifacts can be corrupted, stale or user-modified.
Jinja autoescape must remain enabled for HTML templates.
Do not render raw HTML from:
- product artifacts;
- adapter responses;
- config values;
- user input;
- markdown converted from untrusted sources;
unless it passes a deliberate sanitization path.
Avoid:
|safeon untrusted values;- inline scripts with user-controlled data;
- raw JSON insertion into HTML without safe serialization;
- dynamic template path selection from user input.
Any file/artifact access must be bounded by explicit roots and allowlists.
Required practices:
- use project/product root paths explicitly;
- validate
run_id,artifact_id,config_id,action_id; - normalize and resolve paths before reading;
- verify resolved paths stay under allowed root;
- reject
.., absolute paths and traversal attempts; - avoid arbitrary filesystem browsing.
beeui artifact browser must never become a general file explorer.
Do not add complexity unless needed.
Good security in beeui usually means:
- fewer moving parts;
- explicit behavior;
- narrow adapter interfaces;
- simple validation;
- bounded serialization;
- stable response envelopes;
- clear refusal states;
- no hidden fallback paths.
Product adapters are a primary trust boundary.
Adapters must:
- expose only product-approved read-models;
- validate input identifiers;
- redact secrets;
- avoid returning full raw config unless sanitized;
- avoid exposing arbitrary file paths;
- return explicit partial/error states;
- keep optional write/action methods unavailable by default unless explicitly implemented by product-owned bounded callbacks/API;
- never execute product runtime logic unless called through a bounded action path.
Adapters must not:
- call broker/live APIs directly from UI routes;
- bypass product guardrails;
- mutate product runtime artifacts from read-only routes;
- invent product state;
- silently repair corrupted product artifacts.
Artifact browser must be safe by design.
Allowed:
- listing allowlisted artifacts;
- showing metadata;
- rendering JSON safely;
- rendering JSONL with parse warnings;
- rendering text artifacts as escaped text;
- linking to known source artifacts.
Not allowed:
- arbitrary path browsing;
- editing artifacts;
- deleting artifacts;
- uploading artifacts;
- showing raw secrets;
- following symlinks outside allowed roots;
- rendering untrusted HTML as HTML.
Malformed JSON/JSONL must produce explicit warnings and partial state, not server crashes.
JSON APIs must use stable envelopes.
Recommended envelope:
{
"status": "ok",
"data": {},
"warnings": [],
"errors": [],
"meta": {}
}Error responses should be explicit and safe:
- no stack traces in production responses;
- no secrets;
- no full config dumps;
- no raw sensitive payloads;
- clear reason codes where useful.
API routes must validate:
- path params;
- query params;
- JSON body shape;
- artifact identifiers;
- mode/page/block identifiers.
Config UI must be bounded.
Allowed:
- read-only config read-model;
- redacted config display;
- allowlisted key preview;
- validation preview;
- bounded apply flow with backup and audit.
Not allowed:
- arbitrary YAML editor;
- secrets editing;
- editing broker/live credentials;
- editing product execution internals unless explicitly allowed by product;
- hidden runtime restart/reload;
- writing config without validation;
- writing config without audit.
For config apply:
- require allowlisted keys;
- require stale hash / optimistic guard if implemented;
- validate candidate before write;
- write backup before successful write;
- audit accepted and rejected attempts;
- never serialize full secret-bearing config into audit artifacts.
Bounded actions must be explicit.
Each action should define:
- action id;
- title;
- description;
- required role;
- payload schema;
- validation callback;
- product execution callback;
- allowed/disabled/denied state;
- audit behavior.
Actions must not:
- be generated from arbitrary user-provided code;
- call product internals without adapter boundary;
- bypass product validation;
- introduce live/broker authority unless product explicitly implements and gates it;
- execute in background without visible result/audit.
Every action attempt should produce an audit artifact when action auditing is enabled.
For generic data_table presentation, adapter metadata is limited to explicit
action IDs, controlled escaped labels, bounded string args, text/email fields,
optional bounded confirmation text, and an allowlisted action flow. BeeUI never accepts an action URL,
arbitrary HTML, or JavaScript. The default preview and explicit browser confirmation reduce
accidental execution but do not replace product authorization, validation, CSRF,
or audit. Explicit direct_execute remains limited to the same protected endpoint;
its table refresh failure never creates navigation authority.
When auth is enabled:
- all non-public routes require authentication;
- write/control routes require proper role;
- POST routes require CSRF protection or an equivalent anti-forgery mechanism;
- session cookies must be signed;
- password hashes must be stored safely;
- no default admin password must be committed;
- auth disabled mode must be explicit and intended for local/dev only.
Roles:
viewer— read-only;operator— bounded operator actions;admin— admin/config/support functions.
Session cookie behaviour:
auth.cookie_securecontrols theSecureflag on the session cookie.- Local/dev: set
cookie_secure: false(HTTP allowed). - Remote/customer-safe: set
cookie_secure: true(HTTPS required). - When
auth.enabled=true,auth.cookie_secureis required. auth.cookie_samesitecontrolsSameSite: defaultlax; allowlisted valueslax,strict,none.auth.cookie_samesite=noneis accepted only whenauth.cookie_secure=true.auth.session_age_maxbounds the session lifetime (default86400, allowed range60..604800); expired signed cookies are rejected.- Session cookie setting and deletion share one centralized policy:
AuthService.attach_session_cookie(...)andAuthService.delete_session_cookie(...). - A signed session is created for an already-verified external principal only through the explicit server-side
AuthService.create_principal_session(user_id, role)contract. Browser requests cannot choose or escalaterole;rolemust be an explicitUserRolevalue. - BeeUI does not verify external identity and does not map external credentials to roles; the product backend performs verification and role mapping before issuing a session.
Auth is not required in the first MVP, but when added, it must not be partial or decorative.
- Default framing policy is denial: responses carry
X-Frame-Options: DENY. - Controlled cross-site iframe embedding is enabled only via exact configured origins in
security.frame_ancestors. security.frame_ancestorsaccepts only absolutehttp(s)origins without path, query, fragment, wildcard, CSP keywords or userinfo; malformed/non-origin values fail fast at config load.- When
security.frame_ancestorsis non-empty, BeeUI sendsContent-Security-Policy: frame-ancestors <origins>and omits the conflictingX-Frame-Options: DENY. - Wildcard frame origins are rejected.
Static assets should be controlled.
Allowed:
- vendored Tabler CSS/JS;
- vendored ApexCharts JS (charts);
- vendored Litepicker JS/CSS (datepicker);
- local
beeui.css; - local
beeui.js; - product logo if safely configured.
Avoid:
- loading production assets from uncontrolled CDNs by default;
- copying demo tracking scripts;
- inline scripts with untrusted values;
- user-controlled static asset paths.
If external CDN support is added, it must be explicit and documented.
When dependencies change:
- keep changes intentional and minimal;
- commit both
pyproject.tomlanduv.lock; - review why the package is needed;
- review whether it affects runtime or attack surface;
- avoid dependencies that are unnecessary for KISS MVP.
Do not add dependencies “just in case”.
High-sensitivity dependency areas:
- auth/session packages;
- template/rendering packages;
- markdown/HTML sanitization packages;
- file upload or parsing packages;
- HTTP client/server packages;
- admin framework packages.
To keep the process simple, use only the checks that fit the change.
Static review of source code for risky patterns.
Run or consider SAST when a PR changes:
- config parsing;
- auth/session handling;
- adapter boundaries;
- artifact browser;
- file/path handling;
- API request/response handling;
- serialization/deserialization;
- template rendering;
- bounded actions;
- config apply;
- dependency surface.
- secret leakage to logs or responses;
- unsafe file/path usage;
- missing validation;
- unsafe
|safeusage in templates; - dynamic template selection;
- overly broad exception swallowing;
- insecure debug code;
- dangerous dynamic execution;
- fragile parsing of untrusted data;
- write action without audit.
For most code PRs, a simple static safety pass is enough:
- manual review with security mindset;
- plus automated static scan if available.
Software Composition Analysis: dependency review.
Run or consider SCA when:
pyproject.tomlchanges;uv.lockchanges;- a dependency is added, removed or upgraded.
- known vulnerable packages;
- unnecessary packages;
- overly broad dependency additions;
- packages with risky maintenance history;
- packages that increase server/browser attack surface.
If dependencies changed, SCA is required. If dependencies did not change, SCA is usually not needed.
Dynamic testing of exposed web/API behavior.
Run or consider DAST when a change affects:
- HTTP routes;
- request/response handling;
- API endpoints;
- config apply endpoints;
- artifact browser endpoints;
- auth/session routes;
- bounded action routes.
- malformed path params;
- malformed query values;
- malformed JSON bodies;
- path traversal attempts;
- method misuse;
- unsafe redirects;
- unsafe error paths;
- crashes under bad inputs.
For beeui, lightweight DAST-style route checks are useful for web/API changes.
Minimum examples:
- bad
run_id; - bad
artifact_id; - unknown page/block;
- invalid mode;
- invalid config key;
- invalid action payload;
- non-GET request to read-only route.
Interactive testing with runtime instrumentation or deeper runtime observation.
Consider IAST only for higher-risk changes such as:
- auth/session implementation;
- config apply;
- bounded action execution;
- artifact parsing from untrusted/corrupted files;
- standalone service mode with HTTP product adapters.
IAST is not default for everyday work. Use it only when a change is clearly security-sensitive and runtime-observable.
Feeding unexpected or malformed input to fragile code paths.
Consider fuzzing for code that parses or restores:
- JSON;
- JSONL;
- config-like data;
- CLI input;
- HTTP payloads;
- artifact IDs;
- route params;
- custom selector paths;
- adapter responses.
- settings/config validation helpers;
- artifact readers;
- JSONL preview parser;
- selector resolver;
- route param validators;
- config apply payload validator;
- action payload validator.
Do not fuzz everything. Use fuzzing only for code that can realistically break on malformed input.
Use these three practical levels.
Examples:
- docs only;
- comments only;
- test-only changes;
- visual styling without data/API changes;
- non-sensitive template adjustments;
- formatting.
Usually enough:
- normal review;
- targeted tests if needed.
Examples:
- app factory changes;
- config loading;
- page/block schema;
- adapter contract;
- artifact parsing;
- API contract;
- dashboard read-model;
- product integration;
- config preview.
Usually needed:
pytest -q;- web/CLI smoke;
- route checks if web/API changed;
- HTML/API response inspection;
- SAST mindset review.
Examples:
- auth/session logic;
- password/session storage;
- config apply;
- bounded operator actions;
- artifact browser path handling;
- file/path access;
- dependency updates;
- standalone HTTP product adapters;
- user-controlled HTML/markdown rendering;
- secrets redaction logic.
Usually needed:
- all runtime-risk checks;
- SAST;
- SCA if dependencies changed;
- DAST-style route tests if HTTP routes changed;
- targeted fuzzing if parsing/restoring untrusted input;
- deeper runtime review if auth/action/config mutation path changed.
Before opening PR, check:
- are secrets kept out of HTML/API/logs/artifacts?
- are required config keys validated fail-fast?
- did I avoid hidden defaults for sensitive behavior?
- did I keep the change inside the intended scope?
- did I avoid unnecessary abstraction?
- if dependencies changed, were they reviewed?
- if external/product input is parsed, is handling robust enough?
- are artifacts safe to store and inspect?
- are read-only routes actually read-only?
- are write/control routes validated and audited?
- is path traversal blocked where file access exists?
- is HTML autoescape preserved?
During review, ask:
- does this change touch auth, sessions, dependencies, parsing, file paths, config apply or actions?
- does it introduce a new trust boundary?
- are logs still safe?
- are HTML/API responses still safe?
- are artifacts still safe?
- are required validations explicit?
- are product authority boundaries preserved?
- is any check from this document missing?
- is the solution simple enough?
Allowed:
- startup events;
- route registration events;
- high-level adapter events;
- reason codes;
- artifact identifiers;
- sanitized config choices;
- state transitions.
Not allowed:
- raw secret values;
- full env dumps;
- session cookies;
- password hashes;
- bearer tokens;
- API keys;
- full request headers;
- unredacted product configs;
- stack traces in user-facing responses.
Allowed when useful:
- config change audit summary;
- config backup without additional secret exposure beyond existing local file;
- operator action audit summary;
- support diagnostics;
- UI read-model snapshots if intentionally added;
- safe artifact metadata.
Not allowed:
- raw API secrets;
- full sensitive headers;
- env dumps;
- unsafe snapshots that expose credentials;
- arbitrary full product config inside audit artifact;
- hidden runtime state that becomes a second source of truth.
Allowed:
- status;
- reason codes;
- sanitized read-model data;
- safe artifact metadata;
- redacted config values;
- product-provided non-sensitive summaries.
Not allowed:
- secrets;
- raw env;
- raw cookies;
- unredacted config;
- server filesystem absolute paths unless explicitly safe and needed;
- Python tracebacks in normal API responses.
When working with files:
- prefer explicit project/product paths;
- avoid uncontrolled path building from untrusted input;
- validate assumptions before reading stored artifacts;
- do not trust restored JSON blindly;
- reject traversal;
- reject absolute paths from route params;
- keep artifact access allowlisted;
- avoid following symlinks outside allowed roots.
When working with templates:
- keep Jinja autoescape enabled;
- do not use
|safeon untrusted input; - escape artifact text;
- escape JSONL preview text;
- safely serialize JSON for script contexts;
- avoid inline scripts using raw user/product data;
- do not load templates based on user-controlled paths.
When a new config key affects UI/backend behavior:
- define it explicitly in config examples;
- validate it in
beeuiconfig loader; - fail fast if missing or invalid;
- update docs if the contract changed.
When config preview/apply delegates to product validation:
- product validation result must be explicit;
- invalid product config must be rejected;
- BeeUI must not silently repair product config;
- BeeUI must not invent product defaults.
When adding a product integration:
- create a product adapter;
- keep product semantics inside product adapter/read-model;
- keep product runtime behavior inside product;
- define artifact allowlist;
- define config allowlist if config UI is used;
- define action allowlist if bounded actions are used;
- add tests for partial/missing/corrupted product artifacts;
- document integration boundaries in
docs/INTEGRATION.md.
Do not import deep product internals randomly throughout beeui. Product knowledge must be concentrated in the adapter/integration layer.
Standalone mode is future scope and must be treated carefully.
If added:
- HTTP product adapters must have timeouts;
- backend unavailable state must be explicit;
- CORS must be disabled or narrow by default;
- auth boundary must be explicit;
- product API credentials must not be logged;
- degraded backend must not crash entire UI;
- standalone mode must not bypass product validation/action boundaries.
Embedded mode remains preferred for MVP.
Use security as part of the normal workflow:
- identify change level;
- implement minimally;
- run required checks;
- inspect logs/HTML/API/artifacts;
- document verification in PR.
Do not create separate bureaucracy unless the project actually needs it.
Avoid these patterns:
- hidden required defaults in code;
- logging sensitive runtime state;
- dependency additions without review;
- broad refactors mixed with security-sensitive changes;
- arbitrary YAML editor;
- arbitrary artifact filesystem browser;
- direct broker/runtime execution from UI;
- rendering untrusted artifact HTML as HTML;
- using
|safeto “fix” display issues; - turning
beeuiinto a second product runtime; - “future-proof” abstractions that increase risk and complexity;
- marking every PR as requiring every type of security testing.
To keep this lightweight:
- most PRs need normal review + tests;
- web/API PRs need route checks;
- artifact/file PRs need path traversal and malformed file checks;
- code-heavy adapter/API PRs need SAST mindset review;
- dependency PRs need SCA;
- auth/config-apply/action PRs are security-sensitive;
- fuzzing is targeted, not mandatory everywhere.
Security in beeui should stay practical.
The main rules are:
- keep product source of truth in the product;
- read-only by default;
- protect secrets;
- validate config explicitly;
- keep logs safe;
- keep HTML/API responses safe;
- keep artifacts safe;
- review dependencies;
- block path traversal;
- preserve product authority boundaries;
- use only the security checks that match the real risk;
- keep everything simple enough to maintain.