Commit Graph
7 Commits
Author SHA1 Message Date
Bobby Ho 9e8075db0f fix: prevent markdown injection in notifications (#28340)
First of two PRs.

Notification title and body templates are Markdown authored by Coder,
but the label values interpolated into them are user-controlled and were
substituted through `text/template`, which does no escaping. Those
values arrive from user profile fields and from OIDC/GitHub name claims.

This PR:

- Neutralizes Markdown structure in label, data, and `UserName` values
before they reach the template. Applied in `notifier.prepare`, so
already-queued messages are covered and the stored payload keeps its
original values for webhook consumers. Nested `.Data` map keys are
escaped too: one shipped template prints a key, and those keys are
Terraform resource addresses.
- Narrows the notification Markdown grammar to what templates actually
use. `CommonExtensions` enabled Tables, DefinitionLists and MathJax,
each openable from a value and used by no template. Autolink stays off
so a URL in a value cannot become an anchor.
- Enables `html.Safelink`, restricting generated hrefs to safe schemes,
and guards the panic it exposes: `parser.IsSafeURL` slices a destination
before bounds-checking it, so `[docs]()` crashed both renderers.
- Folds line breaks out of the `Subject:` header and encodes it, fixing
a pre-existing RFC 2047 violation for non-ASCII subjects, a forged
encoded-word that let a value choose the displayed subject, and headers
running past RFC 5322's 998-octet line limit.

Escaping is narrow on purpose, split by where each character carries
meaning:

- `` \[]()!<` `` everywhere. Backtick is in this group because a fenced
block's info string is an HTML sink: gomarkdown writes it into
`class="language-..."` unescaped, and `SkipHTML` does not apply to a
`CodeBlock` node, so a value that closes the attribute and the tag
injects live markup.
- `#-+.>|` only in leading position, so values like `bobby-workspace`
and `1.5` are untouched.
- `=`, `~` and `:` are not escapable by both renderers, so the preceding
line break is folded instead. `:` opens a definition list and a GFM
table delimiter row that escaping `|` cannot reach. A value's *first*
line has no preceding break to fold, so a real tilde fence or `===`
underline is escaped there instead, accepting a visible backslash: an
unterminated `~~~` at the start of a title otherwise renders the
Subject, `<title>` and heading empty.
- Leading indentation is truncated to three spaces. Four open an
indented code block and a space has no escape.
- Emphasis characters are left alone. Escaping `_` corrupts label values
such as `user_override` that body templates compare with `eq`, which
silently drops content from the rendered email.

One golden file changes: the resource replacements `body_markdown` now
reads `docker_container\[0\]`, from the map-key escaping above. Every
other golden is byte-identical.

**One known residual**, pinned by a test that fails if it closes:
CommonMark does not process escapes inside a code span, so where a
template wraps a value in one, as the workspace out-of-disk body does,
the escaper's own backslashes reach the reader. That depends on where
the value lands rather than what it contains, which a pre-render escaper
cannot see. This narrows the class rather than closing it.

**#28397 completes the fix and is stacked on this branch. This PR should
not merge without it.**

Escaping here cannot reach the SMTP HTML template's sinks, by design
rather than by oversight: the subject is produced by
`PlaintextFromMarkdown`, which strips exactly the backslashes added
here, and `html.gotmpl` then interpolated the result through
`text/template`. On this branch alone, a label value still reaches the
Subject, `<title>` and `<h1>` as live markup. #28397 escapes at those
sinks with `| html`, which is the only place the information needed to
escape correctly exists.
2026-08-25 08:12:00 -07:00
Vincent Vielle 522181fead feat(coderd): add new dispatch logic for coder inbox (#16764)
This PR is [resolving the dispatch part of Coder
Inbocx](https://github.com/coder/internal/issues/403).

Since the DB layer has been merged - we now want to insert notifications
into Coder Inbox in parallel of the other delivery target.

To do so, we push two messages instead of one using the `Enqueue`
method.
2025-03-05 22:43:18 +01:00
Marcin Tojek 6de59371ea feat: notifications: report failed workspace builds (#14571) 2024-09-18 09:11:44 +02:00
Joobi S B 3301212972 feat: turn off notification via email (#14520) 2024-09-11 11:10:24 -03:00
Marcin Tojek d488853393 fix: notifications: use username in workspace URLs (#14011) 2024-07-25 12:02:24 +02:00
Danny Kopping b2dab3308d feat: implement observability of notifications subsystem (#13799) 2024-07-11 10:57:49 +02:00
Danny Kopping bdd2caf95d feat: implement thin vertical slice of system-generated notifications (#13537) 2024-07-08 15:38:50 +02:00