mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 12:54:03 +00:00
docs: OpenThreat, one file a security tool serves about what it found in the open (#167)
* docs: OpenThreat, one file a security tool serves about what it found in the open Twelve rules that degrade and two that do not: a subject is public or it is not in the file (no private repos, no customer servers, no paid users' scans), and a secret is never located while it is open (rule, severity, subject, status only; no location, message or excerpt). Four kinds: finding, attack, indicator, advisory. Status open, fixed, mitigated, blocked, withdrawn; a withdrawn threat stays a while so directories retract it. Announcing is on by default with a one-switch opt-out in the tool's own settings. Discovery at /.well-known/openthreat.json, rel="openthreat", or a handed URL; origin is the verification. Mapped against SARIF, STIX 2.1 and CSAF rather than replacing them. First reporter: threatcrush.com/discovery (its own PR). First directory: nichedb.dev/c/threats (its own PR). Registered in DOC_SLUGS, NAV, STATIC_ROUTES and llms.txt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ * ci: trigger workflows --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
938bd5f632
commit
0fe1d423df
6 changed files with 375 additions and 0 deletions
|
|
@ -33,6 +33,7 @@ export function GET(): Response {
|
|||
- [OpenCoupon](${SITE_URL}/opencoupon): One file a merchant serves about what is on offer right now, at /.well-known/opencoupon.json: every code, sale and shipping threshold with kind, value, scope, dates, status and regions, expired codes kept so directories learn they died. A coupon site reads the merchant instead of a forum thread.
|
||||
- [OpenRecipe.md](${SITE_URL}/openrecipe): One Markdown file that is a recipe: summary block (Serves, Prep, Cook, Cuisine, Diet, Author, Source), ingredients and steps as written, notes, nutrition; served next to the page or linked with rel="openrecipe"; schema.org/Recipe JSON-LD is derived from it, never the reverse.
|
||||
- [OpenAffiliate](${SITE_URL}/openaffiliate): One file a merchant serves about the commission it pays, at /.well-known/openaffiliate.json: programs with what pays (sale, subscription, signup, lead, install), percent or amount, attribution window, hold days and payout methods; four calls let a person or an agent join with an OpenProfile.md, link with ?oa=code, read its own ledger and get paid to its own address. No network in the money; reference implementation crawlproof.com/affiliate.
|
||||
- [OpenThreat](${SITE_URL}/openthreat): One file a security tool serves about what it found in the open, at /.well-known/openthreat.json: findings in public repositories, attacks on the reporter's own infrastructure, indicators and advisories, with severity, rule, subject and status. Private subjects are never in it, secrets are never located while open, announcing is on by default with a one-switch opt-out. First reporter threatcrush.com/discovery, first directory nichedb.dev/c/threats.
|
||||
- [AgentSwarm](${SITE_URL}/agent-swarm): Provider-neutral agent orchestration, model routing, and cost controls.
|
||||
- [AgentByte](${SITE_URL}/agentbyte): Agent screening sessions, policy events, and APIs.
|
||||
- [Credential Sharing](${SITE_URL}/credential-sharing): End-to-end-encrypted team vaults, plus source/target credential diffs, approval, sync, rollback, and audit.
|
||||
|
|
|
|||
196
apps/logicsrc-web/src/app/openthreat/page.tsx
Normal file
196
apps/logicsrc-web/src/app/openthreat/page.tsx
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
import Link from "next/link";
|
||||
import type { ReactNode } from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { SiteShell } from "@/components/site-shell";
|
||||
import { mono, pre, table, td, th } from "../openontology/ui";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "OpenThreat · LogicSRC",
|
||||
description:
|
||||
"OpenThreat is one file a security tool serves about what it found in the open, at /.well-known/openthreat.json: findings in public repositories, attacks on the reporter's own infrastructure, indicators and advisories, with severity, rule, subject and status. Private subjects are never in it and secrets are never located while open.",
|
||||
alternates: { canonical: "/openthreat" }
|
||||
};
|
||||
|
||||
const DESCRIPTOR = `{
|
||||
"openthreat": "0.1",
|
||||
"reporter": { "name": "ThreatCrush", "web": "https://threatcrush.com", "tool": "threatcrush",
|
||||
"policy": "https://threatcrush.com/discovery#policy" },
|
||||
"updated": "2026-09-13T06:00:00Z",
|
||||
"threats": [
|
||||
{ "id": "3f9a1c2b", "kind": "finding", "title": "SQL assembled by concatenation",
|
||||
"severity": "high", "rule": "js-sql-string-building", "cwe": "CWE-89", "category": "code",
|
||||
"subject": { "name": "northwind/api", "url": "https://github.com/northwind/api", "ref": "main" },
|
||||
"location": { "file": "src/db/users.ts", "line": 42 },
|
||||
"status": "open", "last_seen": "2026-09-13T05:40:00Z" },
|
||||
{ "id": "b71e0d44", "kind": "finding", "title": "Hardcoded credential",
|
||||
"severity": "critical", "rule": "secret-generic-credential", "cwe": "CWE-798", "category": "secret",
|
||||
"subject": { "name": "northwind/api", "url": "https://github.com/northwind/api" },
|
||||
"status": "open" },
|
||||
{ "id": "ssh-91.232.105.3", "kind": "attack", "title": "SSH brute force", "severity": "medium",
|
||||
"source": { "ip": "91.232.105.3", "country": "RU" }, "target": { "port": 22, "service": "ssh" },
|
||||
"indicators": [{ "type": "ip", "value": "91.232.105.3" }],
|
||||
"status": "blocked", "count": 47, "last_seen": "2026-09-13T04:52:00Z" }
|
||||
]
|
||||
}`;
|
||||
|
||||
const KINDS: Array<[string, string]> = [
|
||||
["finding", "Something in a public subject's code or configuration: a rule, a CWE, a location."],
|
||||
["attack", "Traffic observed against the reporter's own infrastructure: source, target, count."],
|
||||
["indicator", "A value worth blocking or watching on its own: ip, cidr, domain, url, hash, ua."],
|
||||
["advisory", "A statement about a vulnerability, with the document in refs."]
|
||||
];
|
||||
|
||||
const HARD: Array<[string, string]> = [
|
||||
["A subject is public or it is not in the file", "A private repository, a customer's server, a paying user's scan: none of it is a threat in the open, it is someone's private security posture. A reporter that scans private things keeps two tables and serves one."],
|
||||
["A secret is never located while it is open", "A secret finding is published with rule, severity, subject and status only. No location, no message, no excerpt. The credential is already exposed; the file must not be the map to it."]
|
||||
];
|
||||
|
||||
const ABSENT: Array<[string, string]> = [
|
||||
["No private subjects", "Stated in the rules and worth stating twice."],
|
||||
["No exploit detail", "message says what was found; consequence what it means. How to use it is nobody's business here."],
|
||||
["No scoring across reporters", "severity is the reporter's. A directory that normalises labels the result as its own."],
|
||||
["No push", "A reporter serves a file. A directory watches updated."]
|
||||
];
|
||||
|
||||
export default function OpenThreatPage(): ReactNode {
|
||||
return (
|
||||
<SiteShell active="OpenThreat">
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<p className="eyebrow">LogicSRC standards surface</p>
|
||||
<h2>OpenThreat</h2>
|
||||
<p>
|
||||
One file a security tool serves about what it found in the open. A directory reads the
|
||||
reporter instead of a vendor feed, and the reporter decides what it discloses.
|
||||
</p>
|
||||
</div>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
Every security tool finds things, and every one keeps what it found behind its own login.
|
||||
A scanner that runs on a thousand public repositories knows which rules fire and where,
|
||||
and says nothing, because saying it would mean a feed, a schema, an API key and a sales
|
||||
call. The threat feeds that exist are products with terms that forbid redistribution.
|
||||
OpenThreat is the small file a tool can serve in an afternoon at{" "}
|
||||
<code style={mono}>/.well-known/openthreat.json</code>, with a rule for what may go in
|
||||
it.
|
||||
</p>
|
||||
<p style={{ color: "#5b6b7a" }}>
|
||||
Status: 0.1. The first reporter is{" "}
|
||||
<a href="https://threatcrush.com/discovery">threatcrush.com/discovery</a>, built from the
|
||||
scans its GitHub App ran on public repositories; the first directory is{" "}
|
||||
<a href="https://nichedb.dev/c/threats">nichedb.dev/c/threats</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>The descriptor</h2>
|
||||
<p>
|
||||
Only <code style={mono}>reporter.name</code> and a threat's{" "}
|
||||
<code style={mono}>title</code> are required. Everything at{" "}
|
||||
<code style={mono}>/.well-known/</code> is TLP:CLEAR by definition.
|
||||
</p>
|
||||
</div>
|
||||
<pre style={pre}>{DESCRIPTOR}</pre>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
<code style={mono}>rule</code> is the same string a SARIF ruleId carries;{" "}
|
||||
<code style={mono}>subject</code> is what the threat is about and is public by
|
||||
definition; <code style={mono}>status</code> is open, fixed, mitigated, blocked or
|
||||
withdrawn, and a withdrawn threat stays in the file a while so directories retract it.
|
||||
The second threat above is a secret: no location, no message, by rule.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Four kinds</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={th}>kind</th>
|
||||
<th style={th}>what it is</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{KINDS.map(([kind, what]) => (
|
||||
<tr key={kind}>
|
||||
<td style={td}>
|
||||
<code style={mono}>{kind}</code>
|
||||
</td>
|
||||
<td style={td}>{what}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Two rules that do not degrade</h2>
|
||||
<p>Every other rule degrades. These two are the reason the file can exist at all.</p>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<tbody>
|
||||
{HARD.map(([what, why]) => (
|
||||
<tr key={what}>
|
||||
<td style={td}>
|
||||
<strong>{what}</strong>
|
||||
</td>
|
||||
<td style={td}>{why}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
A subject that was scanned did not ask to be listed. Announcing is on by default, because
|
||||
a finding in a public repository is public already, and opting out is one switch in the
|
||||
tool's own settings. A subject that opts out leaves the file on the next build, and
|
||||
is served once more as <code style={mono}>withdrawn</code> so directories retract it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>What is deliberately absent</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<tbody>
|
||||
{ABSENT.map(([what, why]) => (
|
||||
<tr key={what}>
|
||||
<td style={td}>
|
||||
<strong>{what}</strong>
|
||||
</td>
|
||||
<td style={td}>{why}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Where everything lives</h2>
|
||||
</div>
|
||||
<ul style={{ color: "#41505d", lineHeight: 1.9, paddingLeft: "1.1rem" }}>
|
||||
<li>
|
||||
<Link href="/docs/openthreat">Specification</Link>: the descriptor, twelve rules and the
|
||||
two that do not degrade, announcing and opting out, discovery, SARIF, STIX and CSAF
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://threatcrush.com/discovery">threatcrush.com/discovery</a>: the first
|
||||
reporter, and its policy page
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://nichedb.dev/c/threats">nichedb.dev/c/threats</a>: the first directory,
|
||||
with RSS, JSON, API and MCP over the same rows
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/openprofile">OpenProfile.md</Link>, the operator behind a reporter;{" "}
|
||||
<Link href="/openserver">OpenServer</Link> and <Link href="/opencoupon">OpenCoupon</Link>
|
||||
, the same serve-your-own-file shape for other niches
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</SiteShell>
|
||||
);
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ const STATIC_ROUTES: Array<{
|
|||
{ path: "/openmcp", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openaccess", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openserver", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openthreat", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/opencpu", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openmemory", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/opengpu", changeFrequency: "weekly", priority: 0.9 },
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const NAV: Array<{ href: string; label: string; external?: boolean }> = [
|
|||
{ href: "/openmcp", label: "OpenMCP" },
|
||||
{ href: "/openaccess", label: "OpenAccess" },
|
||||
{ href: "/openserver", label: "OpenServer" },
|
||||
{ href: "/openthreat", label: "OpenThreat" },
|
||||
{ href: "/opencpu", label: "OpenCPU" },
|
||||
{ href: "/openmemory", label: "OpenMemory" },
|
||||
{ href: "/opengpu", label: "OpenGPU" },
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export const DOC_SLUGS = [
|
|||
"openmcp",
|
||||
"openaccess",
|
||||
"openserver",
|
||||
"openthreat",
|
||||
"openfile",
|
||||
"opendisk",
|
||||
"opencoupon",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue