Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ All notable changes to OriginWeave are documented in this file. The format follo

### Added

- Bound explicit extension-to-Agent grants to exclusive trusted-time expiry in addition to extension identity, session, browsing context, and canonical origin, so a same-origin grant cannot be reused at or after the deadline.
- Bound explicit extension-to-Agent grants to the exact canonical origin in addition to extension identity, session, and browsing context, so a same-session navigation or port change cannot reuse the grant.
- Rust workspace for independently reusable core, policy, destination, network, TLS, resource, and evidence modules.
- Canonical HTTPS and loopback-origin boundary with case-normalized schemes and hosts, default-port normalization, IPv4/IPv6 handling, browser-special numeric-host rejection, and explicit malformed-input errors.
- Typed browser actions, capabilities, risk classes, execution modes, robots decisions, secret-delivery contracts, immutable canonical action-intent digests, and intent-bound approval scopes.
Expand Down
52 changes: 52 additions & 0 deletions crates/originweave-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1063,3 +1063,55 @@ pub fn evaluate_extension_access(
}
ExtensionAccessDecision::Allow
}

/// Why a Chrome extension permission cannot authorize an OriginWeave Agent action.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChromePermissionAuthorityError {
/// The permission names a reviewed Chrome compatibility surface, not Agent authority.
CompatibilitySurfaceOnly,
/// The permission is not a reviewed Chrome surface and still grants no Agent capability.
UnrecognizedPermission,
}

const REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS: &[&str] = &[
"bookmarks",
"declarativeNetRequest",
"declarativeNetRequestWithHostAccess",
"downloads",
"history",
"scripting",
"sidePanel",
"storage",
"tabs",
];

/// Refuse to treat a Chrome extension permission as OriginWeave Agent authority.
///
/// A successful `chrome.downloads` compatibility proof, or any other reviewed
/// Chrome permission, never becomes [`Capability::Download`] or any other Agent
/// capability. Adapters must keep Manifest V3 evidence and Agent grants separate
/// and call this boundary before exposing a typed action to policy.
pub fn chrome_permission_authorizes_agent_action(
permission: &str,
action: ActionKind,
) -> Result<(), ChromePermissionAuthorityError> {
let _action = action;
if !is_exact_chrome_permission_token(permission) {
return Err(ChromePermissionAuthorityError::UnrecognizedPermission);
}
if REVIEWED_CHROME_COMPATIBILITY_PERMISSIONS.contains(&permission) {
return Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly);
}
Err(ChromePermissionAuthorityError::UnrecognizedPermission)
}

fn is_exact_chrome_permission_token(permission: &str) -> bool {
let mut characters = permission.chars();
let Some(first) = characters.next() else {
return false;
};
first.is_ascii_lowercase()
&& permission
.chars()
.all(|character| character.is_ascii_alphabetic())
}
38 changes: 38 additions & 0 deletions crates/originweave-core/tests/extension_authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use originweave_core::{
BrowserSessionId, BrowsingContextId, ExtensionAccessDecision, ExtensionAccessRequest,
ExtensionAgentCapability, ExtensionAgentGrant, ExtensionId, evaluate_extension_access,
};
use originweave_core::{
ActionKind, ChromePermissionAuthorityError, chrome_permission_authorizes_agent_action,
};

fn extension_id(value: &str) -> ExtensionId {
ExtensionId::parse(value).expect("valid extension id")
Expand Down Expand Up @@ -144,3 +147,38 @@ fn explicit_grant_can_authorize_multiple_bounded_agent_capabilities() {
);
}
}

#[test]
fn chrome_downloads_permission_cannot_authorize_agent_download() {
assert_eq!(
chrome_permission_authorizes_agent_action("downloads", ActionKind::Download),
Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly)
);
assert_eq!(
chrome_permission_authorizes_agent_action("bookmarks", ActionKind::Download),
Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly)
);
assert_eq!(
chrome_permission_authorizes_agent_action("history", ActionKind::Download),
Err(ChromePermissionAuthorityError::CompatibilitySurfaceOnly)
);
assert_eq!(
chrome_permission_authorizes_agent_action("DOWNLOADS", ActionKind::Download),
Err(ChromePermissionAuthorityError::UnrecognizedPermission)
);
assert_eq!(
chrome_permission_authorizes_agent_action("", ActionKind::Download),
Err(ChromePermissionAuthorityError::UnrecognizedPermission)
);
assert_eq!(
chrome_permission_authorizes_agent_action(
"downloads\nhttps://example.invalid",
ActionKind::Navigate
),
Err(ChromePermissionAuthorityError::UnrecognizedPermission)
);
assert_eq!(
chrome_permission_authorizes_agent_action("cookies", ActionKind::Download),
Err(ChromePermissionAuthorityError::UnrecognizedPermission)
);
}
2 changes: 1 addition & 1 deletion docs/adr/0013-manifest-v3-extension-authority.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ No persistent database migration is introduced. A release can roll back the Chro

## Open follow-ups

- Complete issue #27's compatibility matrix and production isolation acceptance.
- Complete issue #27's compatibility matrix and production isolation acceptance. Exclusive trusted-time expiry on origin-bound `ExtensionAgentGrant` evaluation is the next protected-main candidate; task identity binding remains open.
- Define managed-extension identity/update semantics.
- Implement the native-messaging allow-list/process boundary before claiming support.
- Integrate the complete Agent Task browser vertical slice under issue #28.
Expand Down
12 changes: 12 additions & 0 deletions docs/doctoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ The WHATWG URL host parser and Chromium canonicalizer classify shortened decimal

The exact Chromium regression evidence is pinned to revision `446d05d21720f0b3505ec21057b3e9f909784262`. A mutable `HEAD` reference is not sufficient for a reproducible security contract.

### Extension-to-Agent grant origin binding

RFC 6454 defines a web origin as the scheme, host, and port tuple that browsers use to isolate authority. An OriginWeave `extension_grant` that is bound only to extension identity, session, and browsing context would remain valid after the same context navigates to another origin. OriginWeave therefore requires the grant and the request to carry the same canonical origin. A host change or a non-default port change is a different origin and cannot reuse the grant. This is grant-scope isolation only; it does not install an extension, parse Chrome messages, or mint Agent capabilities from Manifest V3 permissions.

### Extension-to-Agent grant exclusive expiry

RFC 9700 is the current Best Current Practice for OAuth 2.0 security. It requires access tokens to be restricted in lifetime and treats long-lived bearer credentials as a standing authorization risk. An OriginWeave `extension_grant` that matches extension identity, session, browsing context, and canonical origin but has no exclusive expiry remains usable after the Agent Task window ends. OriginWeave therefore requires the grant to carry an exclusive `expires_at_epoch_seconds` deadline and the request to carry trusted `now_epoch_seconds`. Evaluation fails closed when `now >= expires_at`, matching the existing sensitive-handle exclusive-expiry rule. Page, extension, and model clocks are not trusted time. This slice does not bind task identity, install an extension, or mint Agent capabilities from Manifest V3 permissions.

### Resolved destination and redirect safety

Canonical origin identity is not a network-destination authorization. The IANA IPv4 and IPv6 Special-Purpose Address Space registries enumerate blocks whose source, destination, forwardability, globally reachable, and protocol-reserved properties differ. Both registries were last updated on 9 October 2025 and explicitly warn that registry presence does not guarantee routability in a particular local or global context. RFC 6890 established the common special-purpose registry fields, and RFC 8190 replaced the ambiguous `global` field with `globally reachable`.
Expand Down Expand Up @@ -96,6 +104,8 @@ Amazon Web Services. (n.d.). *Set up the Amazon EKS Pod Identity Agent*. Retriev

Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, P., & Roberts, K. (2024). *Artificial intelligence risk management framework: Generative artificial intelligence profile* (NIST AI 600-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.600-1

Barth, A. (2011). *The web origin concept* (RFC 6454). Internet Engineering Task Force. https://doi.org/10.17487/RFC6454

Bonica, R., Cotton, M., Haberman, B., & Vegoda, L. (2017). *Updates to the special-purpose IP address registries* (RFC 8190). Internet Engineering Task Force. https://doi.org/10.17487/RFC8190

Chromium Authors. (n.d.). *Proxy support in Chrome* [Source documentation]. Chromium. https://chromium.googlesource.com/chromium/src/+/a3e71ebfa307d8760eb68b777e2998a869940092/net/docs/proxy.md
Expand Down Expand Up @@ -128,6 +138,8 @@ International Organization for Standardization. (2017). *Information and documen

Koster, M., Illyes, G., Zeller, H., & Sassman, L. (2022). *Robots Exclusion Protocol* (RFC 9309). Internet Engineering Task Force. https://doi.org/10.17487/RFC9309

Lodderstedt, T., Bradley, J., Labunets, A., & Fett, D. (2025). *OAuth 2.0 security best current practice* (RFC 9700). Internet Engineering Task Force. https://doi.org/10.17487/RFC9700

Microsoft. (2025, July 25). *Azure IP address 168.63.129.16 overview*. Microsoft Learn. https://learn.microsoft.com/azure/virtual-network/what-is-ip-address-168-63-129-16

Nielsen, S., Cetin, E., Schwendeman, P., Sun, Q., Xu, J., & Tang, Y. (2025). *Learning to orchestrate agents in natural language with the Conductor* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2512.04388
Expand Down
2 changes: 1 addition & 1 deletion docs/doctoring/mv3-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

OriginWeave uses Chromium as its compatibility kernel, so browser-extension compatibility must be demonstrated with executable Chromium evidence rather than inferred from architecture alone. The protected-main lane exercises a controlled unpacked Manifest V3 extension against one exact Chrome for Testing build and proves service-worker, content-script, storage, declarative-network-request, tabs, windows, scripting, commands, side-panel, bookmarks/history read compatibility, restart persistence, repeatability, and one real WebDriver click/post-condition. Active stacked compatibility work adds downloads, bounded bookmark/history mutation, profile isolation, explicit extension update/version-migration evidence, and an exact content-script isolated-world check. OriginWeave does **not claim 100% Chrome extension compatibility**.

The checked-in fixture is intentionally local-only. Its host permission is limited to loopback HTTP used by the deterministic test server. It contains no remote code, user credential, model call, external content, native-messaging host, or production PII. Chrome permissions remain distinct from the explicit OriginWeave extension-to-Agent grant implemented in `originweave-core`. Compatibility mutation tests create only controlled synthetic state inside the ephemeral test profile and must clean it up; successful API compatibility never grants the OriginWeave Agent ambient bookmarks/history/downloads authority.
The checked-in fixture is intentionally local-only. Its host permission is limited to loopback HTTP used by the deterministic test server. It contains no remote code, user credential, model call, external content, native-messaging host, or production PII. Chrome permissions remain distinct from the explicit OriginWeave extension-to-Agent grant implemented in `originweave-core`. `chrome_permission_authorizes_agent_action` refuses Chrome `downloads` and other reviewed compatibility permissions as Agent download or any other Agent action. Compatibility mutation tests create only controlled synthetic state inside the ephemeral test profile and must clean it up; successful API compatibility never grants the OriginWeave Agent ambient bookmarks/history/downloads authority.

## Supported-capability evidence matrix

Expand Down
2 changes: 1 addition & 1 deletion docs/traceability/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ ADR lifecycle is separate and remains `Proposed`, `Accepted`, `Superseded`, `Dep
| Structured observation precedes raw HTML/screenshot fallback | ACCEPTED_ARCHITECTURE | PRD-OBS-003; TRD Section 7 | Active PR #52 supplies a non-shipped bounded semantic value primitive; real browser observation and fallback adapters remain Planned |
| WebDriver BiDi / CDP / WebMCP / MCP are adapters, not internal authority | ACCEPTED_ARCHITECTURE | PRD Section 9.8; TRD Section 12 | Protocol adapter implementation remains Planned/active under issue #28; active PR #40 may not be called shipped |
| Manifest V3 compatibility is preserved upstream where practical | PARTIAL | ADR 0001; issue #27; Proposed ADR 0013 | Protected main has pinned real-Chromium compatibility evidence for service worker/content script/storage/DNR/tabs/windows/scripting/commands/side panel/bookmarks/history/restart/repeatability; active PR #43 adds real bounded downloads evidence; full issue #27 matrix remains incomplete |
| Extension permission does not imply OriginWeave Agent capability | PARTIAL | protected-main extension authority kernel; Proposed ADR 0013 | Core extension-to-Agent authority isolation exists on protected main; complete managed-extension/native-messaging/enterprise release policy remains incomplete |
| Extension permission does not imply OriginWeave Agent capability | PARTIAL | protected-main extension authority kernel; Proposed ADR 0013 | Core grant evaluation plus `chrome_permission_authorizes_agent_action` refuse Chrome `downloads` and other reviewed permissions as Agent capability; complete managed-extension/native-messaging/enterprise release policy remains incomplete |
| WARC/PROV-oriented durable evidence adapters | PLANNED | ADR 0003; PRD-EVD-005 | Source/provenance kernel foundation exists; persistence/export adapters remain Planned |
| Origin Map visualizes value/action provenance | PLANNED | PRD-EVD-004; this traceability record | No shipped UI claim |
| Browser / Runtime / Observe / Capture / Governor / Policy / Evidence / Protocol / SDK product surfaces | PARTIAL | PRD Section 6 | Some foundations exist under crates; named commercial surfaces are not all shipped artifacts |
Expand Down
6 changes: 6 additions & 0 deletions docs/traceability/extension-authority-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ Exact head `e83749acd1cf5a0b778ba38eb9d6ed5a9bd1e68f` deliberately keeps only th

The exact head has successful CI, exact owned production coverage, Security Scan, SAST and CodeRabbit status and is Ready for review. It has no raw secret bytes and does not create approval evidence, a broker, browser-fill adapter, protected-value store, KMS path, authenticated workload identity, persistence owner, or release claim.

### Origin-bound extension grant evaluation

**Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR`

The current origin-binding slice requires `ExtensionAgentGrant` and `ExtensionAccessRequest` to carry the same canonical origin. A same-session, same-context request for `https://other.example` or `https://app.example:8443` against a grant for `https://app.example` is `DenyOriginMismatch`. Exclusive trusted-time expiry is evaluated after that origin match: `now >= expires_at` is `DenyExpired`. This does not install an extension, parse Chrome messages, bind task identity, or mint Agent capabilities from Manifest V3 permissions.

## 4. Security interpretation

The executable authority chain is intentionally non-transitive:
Expand Down
Loading