Skip to content

Add draft threat model + SECURITY.md/AGENTS.md discoverability#769

Merged
sergehuber merged 4 commits into
apache:masterfrom
potiuk:asf-security/threat-model-2026-06-02
Jun 11, 2026
Merged

Add draft threat model + SECURITY.md/AGENTS.md discoverability#769
sergehuber merged 4 commits into
apache:masterfrom
potiuk:asf-security/threat-model-2026-06-02

Conversation

@potiuk

@potiuk potiuk commented Jun 2, 2026

Copy link
Copy Markdown
Member

What this is

A draft threat model for Apache Unomi, proposed by the ASF Security team for the Unomi PMC to review, correct, or reject. It is a starting point for discussion, not a finished document — drafted by the Security team's threat-model tooling from Unomi's public docs, repository, and published CVE advisories, following the ASF Security threat-model rubric.

This PR:

  • adds THREAT_MODEL.md — the draft model;
  • adds SECURITY.md — a short security policy that links the threat model;
  • adds AGENTS.md with a ## Security section, so the chain AGENTS.md → SECURITY.md → THREAT_MODEL.md is mechanically discoverable by automated security scanners.

How to read it

Every claim is provenance-tagged: (documented) (from Unomi's docs/repo/CVE advisories), (inferred) (reasoned from architecture/history, not yet confirmed), (maintainer) (confirmed by the PMC). This v0 is ~16 documented / ~30 inferred. The §14 Open questions section collects every inferred claim into waves for the PMC to confirm or correct — that is where review time is best spent. The model is built around Unomi's documented threat history (the OGNL/MVEL expression-evaluation CVEs) and treats the public context endpoint as the primary boundary, with JSON-Schema event validation and the post-CVE expression restrictions as the defenses. The highest-impact open questions:

  • the public-context-endpoint vs. authenticated-admin-API trust split and its defaults (wave 1);
  • whether JSON-Schema validation + the expression allow-list are the on-by-default public-boundary defenses (wave 2);
  • that OGNL/MVEL expression power is by-design for trusted admin-authored conditions, so a finding is only VALID when public input reaches it (wave 3).

Nothing here is a requirement — the model is for the PMC to own. Comment inline, edit the branch, or reply on the email thread.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds security-documentation entry points to make Unomi’s security posture and triage guidance easier to discover (for humans and automated scanners), centered around a draft threat model intended for PMC review and refinement.

Changes:

  • Added a draft THREAT_MODEL.md outlining scope, boundaries, properties, and triage dispositions for security findings.
  • Added SECURITY.md describing ASF-aligned private vulnerability reporting and linking to the threat model.
  • Added AGENTS.md to provide a machine-discoverable pointer chain AGENTS.md → SECURITY.md → THREAT_MODEL.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
THREAT_MODEL.md Introduces a v0 threat model draft, including scope, assumptions, and triage dispositions for findings.
SECURITY.md Adds a security policy with ASF reporting guidance and a link to the threat model.
AGENTS.md Adds an agent-facing index pointing automated tools to SECURITY.md and the linked threat model.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread AGENTS.md Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread THREAT_MODEL.md Outdated
Comment thread THREAT_MODEL.md
| JSON-Schema event validation | schema validation of incoming events | — | **In — the input-validation defense** *(documented: manual `jsonSchema`)* |
| Admin REST + GraphQL APIs | `rest`, `graphql` | network (authenticated) | **In** *(documented: modules)* |
| Persistence | `persistence-elasticsearch` / `persistence-opensearch` | network → ES/OS backend | **In (Unomi's use of it); the backend's own security is operator's** *(inferred)* |
| Plugins / extensions / connectors | `plugins`, `extensions`, `connectors` | varies | **In core ones; third-party/`samples` out** *(inferred)* |
Comment thread THREAT_MODEL.md
| REST / GraphQL admin | conditions, rules, segments, queries | **yes, within the authenticated credential's authority** | authn + authz; restrict who may author expressions |
| Condition / rule definitions | MVEL/OGNL expressions | **public: must be no; admin: yes-but-trusted** | keep expression authoring on the trusted side |
| Persistence queries | derived from the above | indirectly | backend hardening; query/scope isolation |
| Plugins / connectors config | operator-supplied | no — operator-trusted | vet third-party plugins |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@sergehuber sergehuber left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution — the provenance-tagging approach (documented / inferred / maintainer) is excellent and the triage disposition table in §13 will be very useful for the PMC. A few findings below, ranging from substantive content gaps to minor advisory items.


Important: multi-tenancy trust boundary missing (THREAT_MODEL.md §2/§4/§8)

The UNOMI-139 multi-tenant platform core landed in master before this PR was opened. TenantService exists in the core API (api/src/main/java/org/apache/unomi/api/tenants/TenantService.java), Profile now carries tenantId, and SecurityService exposes getTenantEncryptionKey(tenantId). Tenant isolation is therefore a first-class concern in the current codebase.

The threat model covers "Profile/scope access control" in §8 but is silent on tenant isolation: whether an authenticated API client for tenant A can access or corrupt tenant B's profiles, segments, or rules. This is a new trust boundary not present in previous releases. It warrants at minimum an open question in §14 Wave 3, and potentially a §8 property claim if the PMC asserts that tenant isolation is enforced by Unomi itself.

Suggested addition to §14 Wave 3:

"What is the tenant isolation model? Can an API client with credentials for tenant A read or modify tenant B's profiles, segments, or rules — and is this boundary enforced by Unomi or delegated to the integrator?"


Important: /eventcollector endpoint missing from public boundary (THREAT_MODEL.md §2/§4/§6)

The model consistently refers to the public ingestion surface as the "/context.json-style" endpoint, but there is a second equally public servlet: EventsCollectorServlet (wab/src/main/java/org/apache/unomi/web/EventsCollectorServlet.java), mounted at /eventcollector, which handles batch event submission from browsers/clients without authentication. Both surfaces accept untrusted event JSON and feed the same processing pipeline.

Naming only /context.json in §2 (component table), §4 (trust boundary), §6 (inputs table), and §7 (adversary model) means a security scanner that finds /eventcollector and consults this model would land in MODEL-GAP rather than being correctly routed to VALID or KNOWN-NON-FINDING.

Suggested fix throughout: "Public context ingestion: /context.json and /eventcollector (EventsCollectorServlet)"


Advisory: SECURITY.md — private list routing

The ASF security process routes security@apache.org reports internally to the project's private list (private@unomi.apache.org). Mentioning this routing destination (as several other ASF projects do in their SECURITY.md) would help reporters and automated tools understand where the report lands without having to know ASF's internal triage flow. Not a policy error — just a useful precision.


Advisory: THREAT_MODEL.md §5a — naming the protected-events mechanism

The §5a description of the "protected events / third-party-server key concept" is accurate — ThirdPartyServer in services/src/main/java/org/apache/unomi/services/impl/events/ThirdPartyServer.java confirms the mechanism (server id, key, IP allow-list, allowed event types). The §14 Wave 2 question 5 already asks for PMC confirmation, which is the right ask. One small suggestion: naming the key field in the question (e.g. "the third-party server key config in configuration.adoc") would help the PMC immediately know which properties to look up.

Comment thread AGENTS.md Outdated
limitations under the License.
-->

# Agent Guide for unomi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with the Copilot finding: the header should read # Agent Guide for Apache Unomi to match the canonical project name used throughout all three files and in the GitHub repo metadata. Automated security scanners that pattern-match on project names will look for "Apache Unomi", not "unomi".

@potiuk

potiuk commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

Thanks @sergehuber — exactly the kind of review that makes the model accurate; all four are going in.

Tenant isolation (UNOMI-139) — agreed, important. You're right that multi-tenancy is now a first-class boundary (TenantService, Profile.tenantId, SecurityService.getTenantEncryptionKey) and the draft predates it. I'll add the §14 Wave-3 question you suggested verbatim — can an API client for tenant A read or modify tenant B's profiles, segments, or rules, and is that enforced by Unomi or the integrator? — and once the PMC confirms enforcement we promote it to a §8 property (or a §10 downstream responsibility if delegated). Genuine new trust boundary; thank you for catching it.

/eventcollector — agreed, important. Adding EventsCollectorServlet (/eventcollector) alongside /context.json everywhere the public ingestion surface appears (§2 component table, §4 trust boundary, §6 inputs, §7 adversary model) so a scanner that lands there routes correctly instead of MODEL-GAP.

SECURITY.md — adding the private@unomi.apache.org routing note. §5a — naming the ThirdPartyServer key config (server id / key / IP allow-list / allowed event types) in the §14 Wave-2 question so the PMC knows which properties to look up.

I'll push the revision with all four folded in. Thanks again.

…nant isolation, ThirdPartyServer config, private-list routing

- Name the second public ingestion endpoint /eventcollector (EventsCollectorServlet)
  alongside /context.json in the component table and adversary client (so a scanner
  landing on it routes correctly instead of MODEL-GAP).
- Add a Wave-3 open question on tenant isolation (UNOMI-139: TenantService,
  Profile.tenantId, SecurityService.getTenantEncryptionKey) - a new trust boundary.
- Name the ThirdPartyServer key config (server-id / key / IP allow-list /
  allowed-event-types in configuration.adoc) in the Wave-2 protected-events question.
- SECURITY.md: note ASF routes Unomi reports to private@unomi.apache.org.

Generated-by: Claude Opus 4.8 (1M context)
@sergehuber sergehuber merged commit a31a873 into apache:master Jun 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants