Threat model, auth patterns, content-handling rules, and incident response for Make It Rain.
Make It Rain is a client-side Obsidian plugin. It runs inside the user's Obsidian app (Electron) with the user's full vault access. The threats worth caring about:
The plugin holds a Raindrop.io developer token in plain text in the
user's settings (Obsidian's plugin-data JSON). If the user's vault is
synced to a public location, or if a malicious note is rendered with
app.vault.adapter access, the token could leak.
Mitigations:
- Never log the token. (The
secret-scanner.mjsscript greps the codebase; CI runs it.) - Never include the token in error messages, Notices, or rendered note bodies.
- The token is used only in
Authorization: Bearer <token>headers insideapiUtils. Don't construct auth headers anywhere else.
Imported content comes from Raindrop (titles, tags, excerpts, highlights,
archive HTML, attachments). A malicious bookmark could include HTML,
JavaScript, or data: URLs.
Mitigations:
- All remote-source content passes through
securityUtils.sanitizeMarkdownContentbefore being rendered into the note body. securityUtilsdefangs executable code constructs (script tags, inline event handlers,javascript:URIs, etc.).- The Obsidian renderer is itself Markdown-only and ignores most HTML, but defense in depth: don't rely on Obsidian's renderer to keep the user safe.
Raindrop titles, tag names, and collection names are used in file and folder paths. A malicious or malformed name could escape the intended folder.
Mitigations:
fileUtils.sanitizeFileNameis the single chokepoint for user-derived names before anyapp.vaultcall. (See architecture invariants.)- Hard rule: never construct a vault path by string concatenation
outside
fileUtils.
The plugin talks to two domains: the Raindrop.io API and S3 (for binary downloads). Anything else is unexpected.
Mitigations:
- All network calls go through
apiUtils, which restricts to the configured base URL. - The S3 303-redirect follow strips the
Authorizationheader on the second hop, so a redirect to an attacker-controlled host cannot replay the token. - A new outbound domain is a security-relevant change; flag in review.
Downloaded attachments are written to disk as binary. A malformed file with a misleading extension or content-type could cause the user's reader to misbehave.
Mitigations:
downloadUtils.validateBinaryMagicByteschecks the file's actual magic bytes against the extension derived from the HTTPContent-Type.- A mismatch is logged; the file is still written (the user can decide what to do) but a debug file is left next to the note.
- Storage: the Raindrop token lives in the user's plugin data
(Obsidian's
loadData/saveData). It is not committed to the repo. - Transport: Bearer token in the
Authorizationheader. HTTPS only. - Header stripping on redirect: the
Authorizationheader is set per-request and not carried over to a 303 redirect (Obsidian'srequestUrlfollows the redirect with a fresh header set; verify this indownloadUtils). - Rotation: users can rotate the token in Raindrop's settings at any time; the plugin reads the latest value at call time.
The rule is simple: anything from outside our codebase that ends up in a note body is untrusted. New remote-source fields must be added to the sanitization pass before they're written.
| Source | Trusted? | Sanitized? | Where |
|---|---|---|---|
Raindrop title |
No | Yes | securityUtils |
Raindrop excerpt |
No | Yes | securityUtils |
Raindrop note |
No | Yes | securityUtils |
Raindrop tags (user-input) |
No | Yes (format-level) | formatUtils.formatTags + securityUtils |
Raindrop highlights[].text |
No | Yes | securityUtils |
Archive HTML (scrapingUtils) |
No | Yes | htmlToMarkdown + securityUtils |
Static template fragments (in settings.ts defaults) |
Yes | No | N/A — these are the user's own templates, but see T2 |
| User-authored YAML keys | No | Yes (format-level) | yamlUtils.escapeYamlString |
- Dependencies are pinned in
package-lock.json(commit it). handlebarsis currently inpackage.jsonbut unused — see tech-debt-tracker P1. Remove it.- New dependencies are reviewed for: maintenance status, transitive dependencies, and any post-install scripts.
If a security issue is found:
- Open a private issue or contact the maintainer directly (do not open a public PR with a fix before disclosure).
- Cut a patch release as soon as a fix is verified.
- Note the CVE or advisory reference in
CHANGELOG.md. - If the issue involves the token or the sanitization pass, audit recent imports for signs of compromise (no automated signal for this today — a gap worth tracking).
- GitHub: open a security advisory via the repository's Security tab.
- Maintainer: see
package.json→author.