BugbThreat-model preview
Send us a repository.
Get its threat model back.
GuardLink keeps a threat model inside your code as comments. Give us a public GitHub repository and we'll show you what that model looks like for it: the annotations we'd add, the assets they name, and the exposures and data flows they reveal.
What happens after you request a preview
You send a public repository
Paste its GitHub URL and tell us where the preview should go.
We read it with GuardLink
Someone on the Bugb team clones the public repository and annotates it. GuardLink reads source files; it doesn't build or run your code.
The preview arrives by email
You get the suggested annotations and the threat model they produce. Keep them, commit them, or ask us what an exposure means.
What a preview contains
Here is the kind of preview you'd get, built from acme/shop, a fictional sample project we use to show GuardLink. Your preview is written from your own code.
- Suggested annotations
- GuardLink comments written against your actual files and line numbers, ready to commit next to the code they describe.In acme/shop: @exposes, @flows, @comment
- Assets
- The components and data stores worth protecting, named so the rest of the model can refer to them.In acme/shop: #avatar-api, #uploads
- Exposures
- Where an asset is open to a threat, with severity, a CWE where one fits, and the reason in plain words.In acme/shop: 2 high: unrestricted upload, stored XSS
- Data flows
- How data moves between users, services and storage, so trust boundaries are visible.In acme/shop: User → #avatar-api → #uploads → User
// @exposes #avatar-api to #unrestricted-upload [high] cwe:CWE-434 -- "handleAvatarUpload() passes req.headers['x-filename'] to writeFile() with no signature check on the body"// @comment -- "path.basename() stops directory traversal in x-filename; it does not restrict the file type, so #unrestricted-upload stays open"// @flows User -> #avatar-api via HTTPS -- "Raw request body plus x-filename header"// @flows #avatar-api -> #uploads via fs.writeFile -- "Stored under the client-chosen name"export async function handleAvatarUpload(req: IncomingMessage, res: ServerResponse) { const name = path.basename(String(req.headers['x-filename'] ?? 'avatar.png'));Lines omitted await writeFile(path.join(UPLOAD_DIR, name), body);Lines omitted// @exposes #avatar-api to #stored-xss [high] cwe:CWE-79 -- "serveUpload() maps TYPES['.html'] to text/html, so an uploaded .html file renders in the shop origin"// @flows #uploads -> User via HTTPS -- "Content-Type chosen from the stored extension"export async function serveUpload(req: IncomingMessage, res: ServerResponse) {$ guardlink validate .
⚠ 2 unmitigated exposure(s):
#avatar-api → #unrestricted-upload [high] (src/api/avatar.ts:19)
#avatar-api → #stored-xss [high] (src/api/avatar.ts:34)Previews cover public repositories only. A preview is a starting threat model from reading the code; it isn't a penetration test and doesn't prove an exposure is exploitable. We use your contact details to send the preview and follow up about it, as described in our privacy policy.