Cyber Ware takes a defense-in-depth approach to security, combining Rust's compile-time safety guarantees with layered static analysis, runtime enforcement, continuous scanning, and structured development processes. This document summarizes the security measures in place across the project.
- 1. Rust Language Safety
- 2. Compile-Time Tenant Scoping (Secure ORM)
- 3. Authentication & Authorization Architecture
- 4. Credentials Storage Architecture
- 5. Outbound API Gateway (OAGW)
- 6. Compile-Time Linting — Clippy
- 7. Compile-Time Linting — Custom Dylint Rules
- 8. Dependency Security — cargo-deny
- 9. Cryptographic Stack & FIPS-140-3
- 10. Continuous Fuzzing
- 11. Security Scanners in CI
- 12. PR Review Bots
- 13. Specification Templates & SDLC
- 14. Repository Scaffolding — Cyber Ware CLI
- 15. Opportunities for Improvement
Rust eliminates entire categories of vulnerabilities at compile time:
| Vulnerability Class | How Rust Prevents It |
|---|---|
| Null pointer dereference | No null — Option<T> forces explicit handling |
| Use-after-free / double-free | Ownership system with borrow checker |
| Data races | Send/Sync traits enforced at compile time |
| Buffer overflows | Bounds-checked indexing; slices carry length |
| Uninitialized memory | All variables must be initialized before use |
| Integer overflow | Checked in debug builds; explicit wrapping/saturating in release |
Additional Rust-specific project practices:
#[deny(warnings)]— all compiler warnings are treated as errors in CI (RUSTFLAGS="-D warnings")#[deny(clippy::unwrap_used)]/#[deny(clippy::expect_used)]— panicking onNone/Erris forbidden in production code- No
unsafewithout justification — Clippy pedantic rules surface unnecessaryunsafeusage
Source:
libs/modkit-db-macros·guidelines/SECURITY.md·docs/modkit_unified_system/06_authn_authz_secure_orm.md
Cyber Ware provides a compile-time enforced secure ORM layer over SeaORM. The #[derive(Scopable)] macro ensures every database entity explicitly declares its scoping dimensions:
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Scopable)]
#[sea_orm(table_name = "users")]
#[secure(
tenant_col = "tenant_id",
resource_col = "id",
no_owner,
no_type
)]
pub struct Model {
#[sea_orm(primary_key)]
pub id: Uuid,
pub tenant_id: Uuid,
pub email: String,
}Key compile-time guarantees:
- Explicit scoping required — every entity must declare all four dimensions (
tenant,resource,owner,type). Missing declarations cause a compile error. - No accidental bypass —
clippy.tomlconfiguresdisallowed-methodsto block directsea_orm::Select::all(),::one(),::count(),UpdateMany::exec(), andDeleteMany::exec(). All queries must go throughSecureSelect/SecureUpdateMany/SecureDeleteMany. - Deny-by-default — empty
AccessScope(no tenant IDs, no resource IDs) producesWHERE 1=0, denying all rows. - Immutable tenant ownership — updates cannot change
tenant_id(enforced insecure_insert). - No SQL injection — all queries use SeaORM's parameterized query builder.
Source:
docs/arch/authorization/·modules/system/authn-resolver/·modules/system/authz-resolver/·modules/system/tenant-resolver/
Cyber Ware implements a PDP/PEP authorization model per NIST SP 800-162, extended with OpenID AuthZEN 1.0 constraint semantics (see ADR-0001):
Client → AuthN Middleware → AuthN Resolver (token validation)
→ Module Handler (PEP) → AuthZ Resolver (PDP, policy evaluation)
→ Constraints compiled to AccessScope
→ Database (query with WHERE clauses from constraints)
Every authenticated request produces a SecurityContext:
pub struct SecurityContext {
subject_id: Uuid,
subject_type: Option<String>,
subject_tenant_id: Uuid, // every subject belongs to a tenant
token_scopes: Vec<String>, // capability ceiling (["*"] = unrestricted)
bearer_token: Option<SecretString>, // redacted in Debug, never serialized
}bearer_token is stored as Secret<String> — redacted in Debug/Display, never serialized or logged. Introspection caches key by sha256(token), not the raw token.
Source:
OIDC AuthN Plugin DESIGN.md· ADR-0002 · ADR-0003
Validates bearer JWTs via OIDC discovery and JWKS, extracts claims, and constructs the SecurityContext. AuthN and AuthZ are split into independent resolver modules (ADR-0002) with pluggable vendor-specific implementations.
The current OIDC AuthN plugin supports:
- JWT tokens — local validation via OIDC discovery → JWKS → signature verification (
kid,exp, optionalaud), with configurable claim mapping toSecurityContextfields. - Opaque tokens — out of scope for this plugin; non-JWT bearer tokens are rejected.
- S2S identity —
exchange_client_credentials(OAuth2 client credentials grant) for service-to-service calls, producing the sameSecurityContextpipeline. - Caching — JWKS cached with refresh and bounded stale serving; S2S tokens cached with TTL bounded by
min(token_exp - now, configured_ttl).
Source:
DESIGN.md·AUTHZ_USAGE_SCENARIOS.md
Plain AuthZEN point-in-time true/false decisions are insufficient for LIST queries with pagination. The design extends AuthZEN with context.constraints — a predicate DSL so the PEP receives SQL-friendly filters in O(1) PDP calls per query instead of per-row evaluation.
Constraint predicates:
| Predicate | Purpose |
|---|---|
eq(property, value) |
Exact match (e.g., owner_id) |
in(property, values) |
Set membership |
in_tenant_subtree(root_id, barrier_mode, status) |
Hierarchical tenant scoping via tenant_closure |
in_group(group_ids) |
Resource group membership |
in_group_subtree(group_ids) |
Hierarchical group membership |
Constraints OR across alternatives, AND predicates within each constraint. PEP compiles constraints into AccessScope → SecureORM translates to SQL WHERE clauses.
Fail-closed PEP enforcement — PEP denies access on:
- Missing or
falsedecision - Unreachable PDP
- Missing constraints when
require_constraints: true - Unknown predicates or property names
- Empty predicate lists, empty
in/group_idsvalues, or emptyconstraints: []
Capability negotiation — PEP sends capabilities, supported_properties, and require_constraints with each evaluation request. The PDP must not emit unsupported property names and must degrade gracefully (expand groups to explicit in lists, or deny).
Token scopes as capability ceiling — effective_access = min(token_scopes, user_permissions). First-party apps typically carry ["*"] (unrestricted).
Deny contract — decision: false must include a deny_reason with a GTS error_code. Details are logged for audit but never exposed to clients (generic 403 only, no policy leakage).
404 vs 403 for point reads — Constrained queries returning 0 rows yield 404, preventing existence leakage.
TOCTOU mitigation — For UPDATE/DELETE, PEP prefetches the target attribute and uses eq predicates in the WHERE clause so the mutation is atomic with the authorization check.
Hierarchical multi-tenancy with a single-root tree topology (exactly one tenant with no parent; all others descend from it):
- Isolation by default — every resource carries
owner_tenant_idas the primary partition key; tenants cannot access each other's data. - Hierarchical access — parent tenants may access child data. Subject tenant (home identity) and context tenant (operational scope) are distinguished, enabling scoped admin patterns.
- Barriers — child tenants set
self_managed = trueto create a privacy barrier. Parents cannot see that subtree's business data by default;BarrierModecontrols per-resource-type relaxation (e.g., billing ignores barriers while tasks respect them). tenant_closuretable — materialized(ancestor_id, descendant_id, barrier, descendant_status)enables efficientin_tenant_subtreepredicate compilation to SQL subqueries.
Tenant Resolver is a plugin-based system module providing tenant graph operations (get, ancestors, descendants, is_ancestor) via TenantResolverClient:
- Plugin architecture — gateway discovers a backend plugin by GTS vendor string; routes all calls through
TenantResolverPluginClient. Built-in plugins:static-tr-plugin(in-memory tree from config),single-tenant-tr-plugin(enforcesctx.subject_tenant_id()as the only tenant). - Barrier-aware traversal — ancestor/descendant walks respect
self_managedbarriers and use visited sets for cycle safety. - Status filtering — queries filter by
TenantStatus; filtering a suspended parent excludes its entire subtree. - PIP role — Tenant Resolver serves as a Policy Information Point (PIP): the AuthZ plugin queries it for hierarchy data when building tenant constraints.
Source:
RESOURCE_GROUP_MODEL.md
Optional M:N, tenant-scoped resource grouping that acts as a PIP alongside the tenant hierarchy:
- Groups enable attribute-based grouping of resources for authorization (e.g., project groups, organizational units).
- The AuthZ plugin queries group membership/hierarchy when building
in_group/in_group_subtreepredicates. ResourceGroupReadHierarchysupports hierarchical group traversal.- Group constraints are always paired with tenant predicates — defense in depth prevents cross-tenant leakage through group membership alone.
Source: gts-spec ·
dylint_lints/de09_gts_layer/·modules/system/types-registry/
Cyber Ware uses the Global Type System (GTS) as the foundation for attribute-based access control. GTS defines a hierarchical identifier scheme for data types and instances:
gts.<vendor>.<package>.<namespace>.<type>.v<MAJOR>[.<MINOR>]~
How GTS enables ABAC:
- Token claims — authenticated user tokens carry GTS type patterns in
token_scopes, defining the capability ceiling for the subject (e.g.,["gts.cf.core.srr.resource.v1~*"]grants access to all SRR resource types under that schema). - Wildcard matching — GTS supports segment-wise wildcard patterns (
*), chain-aware evaluation, and attribute predicates for fine-grained policy expressions. - Authorization resources — PDP evaluations reference GTS-typed resources (e.g.,
gts.cf.core.oagw.proxy.v1~:invokefor outbound gateway proxy access). - Secure ORM integration (under development) — the
ScopableEntitytrait supports atype_coldimension. The planned flow: AuthZ Resolver (PDP) evaluates GTS type constraints → compiles them intoAccessScope→ Secure ORM translates to SQLWHEREclauses, automatically filtering rows by type at the database level.
Current implementation status:
| Component | Status |
|---|---|
| GTS identifier parsing & validation | Implemented |
| GTS type patterns in token scopes | Implemented |
Wildcard pattern matching (GtsWildcard) |
Implemented |
| GTS → UUID resolution (Types Registry) | Implemented |
| Domain-level type filtering (e.g., SRR) | Implemented |
| GTS-typed authorization resources | Implemented |
Secure ORM type_col auto-injection via PDP |
Under development |
Custom dylint rules (DE0901, DE0902) validate GTS identifier correctness at compile time, preventing malformed type strings from entering the codebase.
Source:
modules/credstore/·modules/credstore/docs/DESIGN.md
Cyber Ware provides a plugin-based credential storage gateway for managing secrets across the platform. The architecture separates the gateway (routing, authorization) from storage backends (plugin implementations).
Consumer → CredStoreClientV1 → Gateway Service → GTS Plugin Discovery
→ CredStorePluginClientV1 (vendor backend)
The SDK enforces secure handling of secret material at the type level:
| Protection | Mechanism |
|---|---|
| Memory safety | SecretValue wraps Vec<u8> with zeroize on Drop — secret bytes are wiped from memory when no longer needed |
| Log safety | Debug and Display implementations on SecretValue emit [REDACTED] — secrets cannot leak through logging |
| Serialization safety | SecretValue does not implement Serialize/Deserialize — secrets cannot be accidentally persisted or transmitted |
| Key validation | SecretRef validates keys as [a-zA-Z0-9_-]+ (max 255 chars, no colons) — prevents injection via key names |
| Anti-enumeration | Failed lookups return Ok(None), not a distinct "forbidden" error — prevents existence probing |
Credentials are scoped along three visibility levels:
- Private —
(tenant, owner, key): only the owning subject within a tenant can access. - Tenant —
(tenant, key): any subject within the tenant can access. - Shared — tenant-scoped with descendant visibility via gateway hierarchy walk-up.
The gateway enforces authorization via SecurityContext; plugins are single-tenant-level adapters that handle storage only. Built-in reference plugin: static-credstore-plugin (YAML-defined, in-memory — development/test use).
The credential storage design specifies AES-256-GCM encryption with per-tenant keys and a KeyProvider abstraction supporting both DatabaseKeyProvider (co-located keys) and ExternalKeyProvider (Vault/KMS integration) for key–data separation.
Source:
modules/system/oagw/·modules/system/oagw/docs/DESIGN.md
OAGW is a centralized outbound API gateway built on Pingora. All platform traffic to external HTTP services is routed through OAGW, enforcing security and observability policies via a Control Plane / Data Plane architecture.
Every proxy request is authorized via PolicyEnforcer before routing:
self.policy_enforcer
.access_scope_with(
&ctx,
&resources::PROXY, // gts.cf.core.oagw.proxy.v1~
actions::INVOKE,
None,
&AccessRequest::new()
.require_constraints(false)
.context_tenant_id(ctx.subject_tenant_id()),
)
.await?;Ancestor bind flows (descendant reusing parent upstream aliases) have separate authorization actions: bind, override_auth, override_rate, add_plugins.
Outbound authentication credentials are never stored in OAGW configuration. Auth configs reference secrets via cred:// URIs, resolved through CredStoreClientV1 under the caller's SecurityContext. OAuth2 client-credentials tokens are cached with keys scoped by (tenant, subject, auth_method), preventing cross-tenant token reuse.
Per-upstream/route authentication plugins modify outbound requests:
| Plugin | Mechanism |
|---|---|
noop |
No authentication (pass-through) |
api-key |
Injects API key from credential store |
oauth2-client-credentials |
Client credentials grant (form/basic), token caching with tenant isolation |
| Control | Protection |
|---|---|
| Path traversal | Alias extracted from first path segment; only suffix is normalized |
| Body size | Configurable cap (default 100 MB) |
| Content validation | Content-Type and Transfer-Encoding validated before forwarding |
| Hop-by-hop headers | Stripped per HTTP spec; internal headers controlled |
| CORS | OPTIONS preflight returns 204 without upstream resolution; real requests validate Origin/method against config |
| Rate limiting | Per-upstream/route limits enforced in the data plane |
| Error isolation | X-OAGW-Error-Source header distinguishes gateway errors from upstream errors; RFC 9457 problem responses |
The project enforces 90+ Clippy rules at deny level, including the full pedantic group. Security-relevant highlights:
| Rule | Why It Matters |
|---|---|
unwrap_used, expect_used |
Prevents panics in production (denial-of-service) |
await_holding_lock, await_holding_refcell_ref |
Prevents deadlocks in async code |
cast_possible_truncation, cast_sign_loss, cast_precision_loss |
Prevents silent data corruption |
integer_division |
Prevents silent truncation |
float_cmp, float_cmp_const |
Prevents incorrect equality checks |
large_stack_arrays, large_types_passed_by_value |
Prevents stack overflows |
rc_mutex |
Prevents common concurrency anti-patterns |
regex_creation_in_loops |
Prevents ReDoS-adjacent performance issues |
cognitive_complexity (threshold: 20) |
Keeps code reviewable and auditable |
clippy.toml additionally enforces:
disallowed-methodsblocking direct SeaORM execution methods (must use Secure wrappers)disallowed-typesblockingLinkedList(poor cache locality, potential DoS amplification)- Stack size threshold of 512 KB
- Max 2 boolean fields per struct (prevents boolean blindness)
Source:
dylint_lints/
Project-specific architectural lints run on every CI build via cargo dylint. These enforce design boundaries that generic linters cannot:
| ID | Lint | Security Relevance |
|---|---|---|
| DE0706 | no_direct_sqlx |
Prohibits direct sqlx usage — forces all DB access through SeaORM/SecORM |
| DE0103 | no_http_types_in_contract |
Prevents HTTP types leaking into contract layer |
| DE0301 | no_infra_in_domain |
Prevents domain layer from importing sea_orm, sqlx, axum, hyper, http |
| DE0308 | no_http_in_domain |
Prevents HTTP types in domain logic |
| DE0801 | api_endpoint_version |
Enforces versioned API paths (/{service}/v{N}/{resource}) |
| DE1301 | no_print_macros |
Forbids println!/dbg! in production code (prevents info leakage) |
The architectural lints in the DE03xx series enforce strict layering (contract → domain → infrastructure), preventing accidental coupling that could undermine security boundaries.
Source:
deny.toml· CI job:.github/workflows/ci.yml(securityjob)
cargo deny check runs in CI and enforces:
- RustSec advisory database — known vulnerabilities are treated as hard errors
- License allow-list — only approved OSS licenses (MIT, Apache-2.0, BSD, MPL-2.0, etc.)
- Source restrictions — only
crates.ioallowed; unknown registries and git sources warned - Duplicate version detection — warns on multiple versions of the same crate in the dependency graph
The project uses aws-lc-rs (via rustls) as its primary TLS cryptographic backend. JWT validation uses jsonwebtoken and aliri.
| Layer | Library | Backend |
|---|---|---|
| TLS | rustls + hyper-rustls |
aws-lc-rs |
| Certificate verification | rustls-webpki |
aws-lc-rs, ring |
| JWT validation | jsonwebtoken, aliri |
sha2, hmac, ring |
| Database TLS | sqlx (tls-rustls-aws-lc-rs) |
aws-lc-rs |
FIPS-140-3 support: the application can be built with FIPS-140-3 approved cryptography by enabling the fips feature flag:
cargo build -p cyberware-server --features fipsThis switches the underlying cryptographic module from aws-lc-sys to aws-lc-fips-sys — the FIPS-validated AWS-LC module (NIST Certificate #4816). At startup, the FIPS crypto provider is installed as the process-wide default before any TLS, database, JWT, or other cryptographic operations occur. Runtime assertions verify that TLS configurations are operating in FIPS mode; the application fails fast if FIPS mode is expected but not active.
Build requirements for FIPS: CMake, Go, C compiler, C++ compiler. These are needed to build the AWS-LC FIPS module with its required integrity checks.
Important: enabling the fips feature does not automatically make the entire application FIPS-140-3 compliant. Full compliance also depends on the deployment environment, operating system, and adherence to the AWS-LC security policy constraints. The ring crate remains in the dependency graph via pingora-rustls (certificate hashing only, not TLS crypto) and aliri (token lifecycle); these do not participate in TLS cryptographic operations.
Source:
fuzz/· CI workflow:.github/workflows/clusterfuzzlite.yml
Cyber Ware uses cargo-fuzz with ClusterFuzzLite for continuous fuzzing. Fuzzing discovers panics, logic bugs, and algorithmic complexity attacks in parsers and validators.
Fuzz targets:
| Target | Priority | Component | Status |
|---|---|---|---|
fuzz_odata_filter |
HIGH | OData $filter query parser |
Implemented |
fuzz_odata_cursor |
HIGH | Pagination cursor decoder (base64+JSON) | Implemented |
fuzz_odata_orderby |
MEDIUM | OData $orderby token parser |
Implemented |
fuzz_yaml_config |
HIGH | YAML configuration parser | Planned |
fuzz_html_parser |
MEDIUM | HTML document parser | Planned |
fuzz_pdf_parser |
MEDIUM | PDF document parser | Planned |
CI integration:
- On pull requests: ClusterFuzzLite runs with address sanitizer for 10 minutes per target
- On main branch / nightly: Extended 1-hour runs per target
- Crash artifacts and SARIF results uploaded for triage
Local usage:
make fuzz # Smoke test all targets (30s each)
make fuzz-run FUZZ_TARGET=fuzz_odata_filter FUZZ_SECONDS=300
make fuzz-list # List available targetsMultiple automated scanners run on every pull request and/or on schedule:
| Scanner | What It Checks | Trigger |
|---|---|---|
| CodeQL | Static analysis for security vulnerabilities (Actions, Python, Rust) | PRs to main + weekly schedule |
| OpenSSF Scorecard | Supply-chain security posture (branch protection, dependency pinning, CI/CD hardness) | Weekly + branch protection changes |
| cargo-deny | RustSec advisories, license compliance, source restrictions | Every CI run |
| ClusterFuzzLite | Crash/panic/complexity bugs via fuzzing with address sanitizer | PRs to main/develop |
| Dependabot | Dependency alerts (including malware), security updates, version updates | Continuous (repository-level) |
| Snyk | Dependency vulnerability scanning | Configured at repository/organization level |
| Aikido | Application security posture management | Configured at repository/organization level |
The OpenSSF Scorecard badge is displayed in the project README:
Every pull request is reviewed by automated bots before human review:
| Bot | Mode | Purpose |
|---|---|---|
| CodeRabbit | Automatic on every PR | AI-powered code review with security awareness |
| Graphite | Manual trigger | Stacked PR management and review automation |
| Claude Code | Manual trigger | LLM-powered deep code review |
Source:
docs/spec-templates/·docs/spec-templates/cyberware-sdlc/
Cyber Ware follows a spec-driven development lifecycle where PRD and DESIGN documents are written before implementation. Security is addressed at multiple points:
- PRD template — Non-Functional Requirements section references project-wide security baselines and automated security scans
- DESIGN template — dependency rules mandate
SecurityContextpropagation across all in-process calls - ISO 29148 alignment — global guidelines reference
guidelines/SECURITY.mdfor security policies and threat models - Testing strategy — 90%+ code coverage target with explicit security testing category (unit, integration, e2e, security, performance)
- Git/PR record — all changes flow through PRs with review and immutable merge/audit trail
Cyber Ware provides a CLI tool for scaffolding new repositories that automatically inherit the platform's security posture:
| Inherited Configuration | Description |
|---|---|
| Compiler configuration | rust-toolchain.toml, workspace lint rules (#[deny(warnings)], 90+ Clippy rules at deny level), unsafe_code = "forbid" |
| Custom dylint rules | Architectural boundary enforcement (DE01xx–DE13xx series), GTS validation (DE09xx) |
| Makefile targets | make deny (cargo-deny), make fuzz (continuous fuzzing), make dylint (custom lints), make safety (full suite) |
| cargo-deny configuration | deny.toml with RustSec advisory checks, license allow-lists, source restrictions |
This ensures every new service or module repository starts with the same defense-in-depth baseline described in this document, eliminating configuration drift across the platform.
The following areas have been identified for future hardening:
- FIPS-140-3 compliance (remaining work) — the
fipsfeature flag enables FIPS-validated TLS viaaws-lc-fips-sys. Remaining: replacering-dependent libraries (alirifor token lifecycle,pingora-rustlsfor certificate hashing) to eliminateringfrom the dependency graph; route JWT and hashing operations throughaws-lc-fips-sys - Secure ORM type-column auto-injection — the
ScopableEntitytrait supports atype_coldimension, but automatic GTS type constraint injection from PDP →AccessScope→ SQLWHEREis under development - Tenant Resolver access-control plugins — the
Unauthorizederror variant is reserved in the SDK, but no production plugin enforces caller-vs-target authorization (the static plugin allows any caller to query any configured tenant; the single-tenant plugin uses identity matching only). A policy-backed plugin would enforce fine-grained tenant visibility - Security guidelines in spec templates — add explicit security checklist sections to PRD and DESIGN templates (threat modeling, data classification, authentication requirements per feature)
- Security-focused dylint lints — extend the
DE07xxseries with additional rules:- Detecting hardcoded secrets or API keys
- Enforcing
SecretString/SecretValueusage for sensitive fields - Flagging raw SQL string construction
- Validating
SecurityContextpropagation in module handlers
- Fuzz target expansion — current implemented targets cover OData parsers (
fuzz_odata_filter,fuzz_odata_cursor,fuzz_odata_orderby). Planned targets:fuzz_yaml_config,fuzz_html_parser,fuzz_pdf_parser,fuzz_json_config,fuzz_markdown_parser - Kani formal verification — expand use of the Kani Rust Verifier for proving safety properties on critical code paths (
make kani) - SBOM generation — add Software Bill of Materials generation to CI for supply-chain transparency
This document is maintained alongside the codebase. For implementation-level security guidelines, see guidelines/SECURITY.md. For the authorization architecture, see docs/arch/authorization/DESIGN.md.