Skip to content
Merged
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: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ own the first two layers or hosted product/account logic.
- Warroom modules infer observable site/action/API/state graphs from evidence;
they do not own product business logic and do not treat LLM output as a gate.
- `docs/reference/` is generated from Python AST and repository assets. It maps
967 maintained Python files, 5,694 declarations, 487 literal module
967 maintained Python files, 5,695 declarations, 487 literal module
registrations, 28 HTTP operations, 108 environment names, CLI parsers,
recipes, bundles, and workflows back to source.

Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [2.31.1]

### Security

- Closed a module-policy bypass in `verify.spec` (GHSA-wmwj-g59x-c8px). The
spec runner picks its child modules out of the caller's own ruleset —
`rules[].source.module` / `rules[].target.module` with free-form params — and
dispatched them with `instance.execute()`. Both locks live in
`BaseModule.run()`, so a caller who had been restricted to `verify.spec`
(`FLYTO_MODULE_ALLOWLIST=verify.spec`, no `FLYTO_GRANTED_PERMISSIONS`) could
name `shell.exec` in a rule and run host commands as the service account,
with neither the module filter nor the `shell.execute` grant consulted. The
dispatcher now calls the policy-gated `run()`, a denied child raises instead
of being reported as an ordinary failed rule, and `POST /v1/execute` gained
the nested-module pre-flight the MCP transport already had, so the ruleset is
refused before `verify.spec` does any work. `_execute_with_resilience` no
longer retries or repackages a `ModulePolicyError` — a blocked module now
reads as blocked rather than broken. A registry-wide test fails on any future
code that resolves a module by a caller-supplied id and calls `execute()`
directly.

### Changed

- `crypto.totp` says when `min_remaining` makes it wait. A code that would
Expand Down
7 changes: 4 additions & 3 deletions SECURITY_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

# Security Status

**Current release: `2.31.1`.** Every advisory published against this project is fixed as of `2.29.0`, and every one has a named regression test that runs in CI.
**Current release: `2.31.1`.** Every advisory published against this project is fixed as of `2.31.1`, and every one has a named regression test that runs in CI.

Installing `>= 2.29.0` clears every known advisory; `2.31.1` is the supported line and the one that receives fixes. See [`SECURITY.md`](SECURITY.md#supported-versions).
Installing `>= 2.31.1` clears every known advisory; `2.31.1` is the supported line and the one that receives fixes. See [`SECURITY.md`](SECURITY.md#supported-versions).

38 advisories have been published and fixed (7 critical, 25 high, 6 medium). They are listed here in full, oldest patch first, because the count is less informative than the pattern: almost all of them are two defects — a caller-supplied path reaching a filesystem sink, and a caller-supplied target reaching the network — found one module at a time.
39 advisories have been published and fixed (8 critical, 25 high, 6 medium). They are listed here in full, oldest patch first, because the count is less informative than the pattern: almost all of them are two defects — a caller-supplied path reaching a filesystem sink, and a caller-supplied target reaching the network — found one module at a time.

## How the recurrence was stopped

Expand Down Expand Up @@ -65,6 +65,7 @@ Applying those audits closed roughly 30 further modules that no advisory had nam
| [GHSA-f9q4-fp8j-r5h7](https://github.com/flytohub/flyto-core/security/advisories/GHSA-f9q4-fp8j-r5h7) | high | `<= 2.28.1` | `2.29.0` | [`test_llm_agent_inline_base_url_is_ssrf_guarded`](tests/core/test_reported_advisories_2026_08_19.py) [`test_llm_agent_reports_ssrf_blocked`](tests/core/test_reported_advisories_2026_08_19.py) |
| [GHSA-pp5w-w9c3-qfv2](https://github.com/flytohub/flyto-core/security/advisories/GHSA-pp5w-w9c3-qfv2) | high | `<= 2.28.1` | `2.29.0` | [`test_llm_agent_inline_base_url_is_ssrf_guarded`](tests/core/test_reported_advisories_2026_08_19.py) [`test_llm_agent_sub_node_config_base_url_is_ssrf_guarded`](tests/core/test_reported_advisories_2026_08_19.py) |
| [GHSA-9x26-9vhm-2qhw](https://github.com/flytohub/flyto-core/security/advisories/GHSA-9x26-9vhm-2qhw) | high | `<= 2.28.1` | `2.29.0` | [`test_client_dsn_cannot_reach_a_private_target`](tests/core/test_reported_advisories_2026_08_19.py) [`test_mongodb_multi_host_dsn_checks_every_host`](tests/core/test_reported_advisories_2026_08_19.py) |
| [GHSA-wmwj-g59x-c8px](https://github.com/flytohub/flyto-core/security/advisories/GHSA-wmwj-g59x-c8px) | critical | `<= 2.31.0` | `2.31.1` | [`test_verify_spec_ruleset_cannot_run_a_denied_module`](tests/core/test_reported_security_advisories.py) |

## Reporting

Expand Down
43 changes: 42 additions & 1 deletion STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

## Current State

- `verify.spec` can no longer be used as a launcher for a module the caller was
denied (GHSA-wmwj-g59x-c8px). Its rules name the child module and its params,
and the dispatcher called `execute()` on them — skipping `BaseModule.run()`,
where both the module filter and the dangerous-permission grant live. Under
`FLYTO_MODULE_ALLOWLIST=verify.spec` with no grants, a ruleset naming
`shell.exec` ran host commands. The child now goes through `run()`, a denied
child raises instead of being reported as a failed rule, and `POST /v1/execute`
applies the nested-module pre-flight the MCP transport already had. A
registry-wide test fails on any future dispatcher that resolves a module by a
caller-supplied id and calls `execute()` directly.

- `crypto.totp` closes the one gap that kept an authenticator-protected site
outside flyto-core: the six digits exist only inside a browser login flow and
no API hands them over. A secret is accepted as the Base32 setup key in any
Expand Down Expand Up @@ -246,7 +257,7 @@
- The 60% line coverage gate measures the maintained orchestration and
security-control kernel. Pluggable module implementations and product
overlays remain covered by catalog, contract, and integration suites.
- Source-backed documentation now covers 967 maintained Python files, 5,694
- Source-backed documentation now covers 967 maintained Python files, 5,695
declarations, 487 literal module registrations, all CLI/HTTP/environment
surfaces (28 static HTTP operations, 108 environment names), and all
maintained recipe/workflow assets. CI rejects drift, missing ownership,
Expand Down Expand Up @@ -356,6 +367,36 @@

## Last Verification

### 2026-08-25 — verify.spec policy-gate bypass (GHSA-wmwj-g59x-c8px): VERIFIED

The reporter's own proof of concept was run against the built artifact, not the
source tree. Installed from PyPI, `flyto-core[api]==2.31.0` reproduces:
`exploit_reproduced: true`, `marker_outside_sandbox: true`, with
`FLYTO_MODULE_ALLOWLIST=verify.spec` and no `FLYTO_GRANTED_PERMISSIONS`.
Installed from the wheel built here, `2.31.1` refuses the same request in all
three reported configurations (default denylist, strict allowlist, and the
`target` rule branch): `bypass_top_level_ok: false`,
`marker_outside_sandbox: false`, error `Module 'verify.spec' declares nested
module(s) blocked by security policy: shell.exec`. The negative control holds in
every run — a direct `shell.exec` request stays blocked.

Repository gates on this tree: project-memory lint PASS, documentation contract
PASS (145 Markdown files, 1266 owned source/config files, 192 local links),
brand PASS, release drift PASS (2.31.1 unreleased), Ruff clean on every changed
file (the four remaining findings are pre-existing and untouched), offline suite
**3175 passed, 11 skipped, 275 deselected**, 63.67% coverage against the 60%
floor, `python -m build` plus `twine check` PASS on both artifacts, `npm audit`
0 vulnerabilities, and strict Indexer `flyto-index verify . --strict --full-scan`
20/20 PASS including the `.flyto-rules.yaml` policy check.

The new regression tests were confirmed to fail on the unpatched code before the
fix landed, so they test the defect rather than the implementation.

Not verified: `flyto-index task validate` could not run against this repo — it
drives the indexer's own interpreter, which has no `pytest-cov`, and its
repository-wide Ruff scan includes `examples/`, which CI does not lint. The
browser and e2e markers were not run.

### 2026-08-12 — capability, extension and runtime closure: VERIFIED

Codex independently reviewed the full working diff and found one additional
Expand Down
2 changes: 1 addition & 1 deletion docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ evidence but does not decide the gate.

- [All 480 active module schemas](TOOL_CATALOG.md)
- [All 487 literal module implementations](reference/registered-modules.md)
- [All 5,694 maintained Python declarations](reference/python-api.md)
- [All 5,695 maintained Python declarations](reference/python-api.md)
- [All CLI parsers](reference/cli.md)
- [All HTTP decorators](reference/http-api.md)
- [All environment readers and packaged workflow assets](reference/configuration.md)
4 changes: 2 additions & 2 deletions docs/MIGRATION_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
| Runtime catalog | 480 modules, 88 categories |
| Literal module registrations | 487 |
| Packaged recipes | 41 |
| Maintained Python source | 967 files, 202,032 lines |
| Python declarations | 5,694 across 818 files |
| Maintained Python source | 967 files, 202,119 lines |
| Python declarations | 5,695 across 818 files |
| Static CLI parsers | Generated in `reference/cli.md` |
| Static HTTP operations | 28 |
| Environment-variable names | 108 |
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ The generated layer makes source coverage auditable without turning narrative
guides into hand-maintained symbol dumps:

- 480 active runtime modules across 88 catalog categories.
- 967 maintained Python files and 5,694 declarations.
- 967 maintained Python files and 5,695 declarations.
- 487 literal module registrations linked to source.
- every static CLI parser and HTTP decorator.
- 108 environment-variable readers.
Expand Down
2 changes: 1 addition & 1 deletion docs/WHITEPAPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The current generated runtime catalog contains 480 modules across 88 categories
and 41 packaged recipes. Catalog search and detail carry each module's
registry-declared `provides_capability` and `plugin`, never a value derived from
the module ID. Source traceability covers 967 maintained Python files,
202,032 lines, and 5,694 class/function/method declarations. These measurements
202,119 lines, and 5,695 class/function/method declarations. These measurements
come from checked generators and are not hand-maintained marketing totals.

## Problem
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/http-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Static FastAPI decorators define **28 operations**. Mount status is explicit: a
| `POST` | `/run` | `run` | internal key | verification service | HTTP operation; linked handler is authoritative. | [`src/core/verification_service.py:447`](https://github.com/flytohub/flyto-core/blob/main/src/core/verification_service.py#L447) |
| `GET` | `/v1/capabilities` | `get_capabilities` | none | Execution API | Deterministic capability manifest for this installation. | [`src/core/api/routes/modules.py:98`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/modules.py#L98) |
| `POST` | `/v1/capabilities/refresh` | `refresh_capabilities` | bearer token | Execution API | Re-run plugin discovery and rebuild the capability manifest. | [`src/core/api/routes/modules.py:118`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/modules.py#L118) |
| `POST` | `/v1/execute` | `execute_module` | bearer token | Execution API | Execute a single module. | [`src/core/api/routes/modules.py:137`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/modules.py#L137) |
| `POST` | `/v1/execute` | `execute_module` | bearer token | Execution API | Execute a single module. | [`src/core/api/routes/modules.py:186`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/modules.py#L186) |
| `GET` | `/v1/extensions` | `list_extensions` | bearer token | Execution API | Installed extensions of every supported kind. | [`src/core/api/routes/extensions.py:183`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/extensions.py#L183) |
| `POST` | `/v1/extensions/install` | `install_extension` | bearer token | Execution API | Install or upgrade one extension. | [`src/core/api/routes/extensions.py:227`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/extensions.py#L227) |
| `GET` | `/v1/extensions/kinds` | `list_extension_kinds` | bearer token | Execution API | The supported extension kinds, served from the same table the installer enforces — so a client's idea of what is installable cannot drift from Core's. | [`src/core/api/routes/extensions.py:205`](https://github.com/flytohub/flyto-core/blob/main/src/core/api/routes/extensions.py#L205) |
Expand Down
Loading
Loading