From 2d82db0afc70069bf368bc8365e41f1b07a3f771 Mon Sep 17 00:00:00 2001 From: maride Date: Mon, 24 Nov 2025 15:06:29 +0100 Subject: [PATCH] Add TLP appendix --- helper.typ | 56 +++++++++++++++++++++++++++++++++++------------------- main.typ | 3 ++- pages.typ | 39 +++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/helper.typ b/helper.typ index fb317e1..050b128 100644 --- a/helper.typ +++ b/helper.typ @@ -1,6 +1,7 @@ #let panicOnPlaceholder = state("panicOnPlaceholder", true) #let hasCIATable = state("hasCIATable", false) #let hasCVSSTable = state("hasCVSSTable", false) +#let usesTLP = state("usesTLP", false) // Function panics if value is not in the allowed array #let panicOnInvalid(value, allowed) = { @@ -167,44 +168,59 @@ ) } +#let tlpLightMap = ( + "RED": (color: rgb("#FF2B2B"), title: "TLP:RED", content: "recipient only"), + "AMBER": (color: rgb("#FFC000"), title: "TLP:AMBER", content: "organisation only"), + "AMBER+STRICT": (color: rgb("#FFC000"), title: "TLP:AMBER+STRICT", content: "organisation\nand its clients"), + "GREEN": (color: rgb("#33FF00"), title: "TLP:GREEN", content: "within community"), + "CLEAR": (color: rgb("#FFFFFF"), title: "TLP:CLEAR", content: "public") +) + +// tlpLabel draws an inline TLP label with appropiate color and black backgropund +// light may be one of "RED", "AMBER", "AMBER+STRICT", "GREEN", or "CLEAR" +#let tlpLabel(light) = { + light = upper(light) + // check argument + panicOnInvalid(light, tlpLightMap.keys()) + + highlight( + fill: black, + text( + weight: "semibold", + fill: tlpLightMap.at(light).color, + tlpLightMap.at(light).title + ) + ) +} + // tlpMark draws a Traffic Light Protocol mark, used on the cover page // light may be one of "RED", "AMBER", "AMBER+STRICT", "GREEN", or "CLEAR" #let tlpMark(light) = { light = upper(light) - let lightMap = ( - "RED": (color: rgb("#FF2B2B"), title: "TLP:RED", content: "recipient only"), - "AMBER": (color: rgb("#FFC000"), title: "TLP:AMBER", content: "organisation only"), - "AMBER+STRICT": (color: rgb("#FFC000"), title: "TLP:AMBER+STRICT", content: "organisation\nand its clients"), - "GREEN": (color: rgb("#33FF00"), title: "TLP:GREEN", content: "within community"), - "CLEAR": (color: rgb("#FFFFFF"), title: "TLP:CLEAR", content: "public") - ) // check argument - panicOnInvalid(light, lightMap.keys()) + panicOnInvalid(light, tlpLightMap.keys()) rect( height: 100%, width: 100%, - stroke: (paint: lightMap.at(light).color.darken(10%), thickness: 2pt, dash: "solid"), + stroke: (paint: tlpLightMap.at(light).color.darken(10%), thickness: 2pt, dash: "solid"), align(center + horizon, grid( columns: (80%), rows: (18pt, auto), gutter: 8pt, - highlight( - fill: black, - text( - size: if light == "AMBER+STRICT" { 13pt } else { 18pt }, - weight: "semibold", - fill: lightMap.at(light).color, - lightMap.at(light).title - ) - ), + [ + #set text(size: if light == "AMBER+STRICT" { 13pt } else { 18pt }) + #tlpLabel(light) + ], text( size: 12pt, - fill: if light == "CLEAR" { black } else { lightMap.at(light).color.darken(10%) }, - lightMap.at(light).content + fill: if light == "CLEAR" { black } else { tlpLightMap.at(light).color.darken(10%) }, + tlpLightMap.at(light).content ) ) ) ) + + usesTLP.update(true) } \ No newline at end of file diff --git a/main.typ b/main.typ index 0f62525..3b6da9e 100644 --- a/main.typ +++ b/main.typ @@ -109,7 +109,8 @@ #(( pages.boxAppendix(), pages.ciaAppendix(), - if helper.hasCVSSTable.get() { pages.cvssAppendix() } + if helper.hasCVSSTable.get() { pages.cvssAppendix() }, + if helper.usesTLP.get() { pages.tlpAppendix() } ).join(pagebreak())) ] ) diff --git a/pages.typ b/pages.typ index 7ca42f6..9a8d807 100644 --- a/pages.typ +++ b/pages.typ @@ -288,3 +288,42 @@ For example: reviewing the source code of a custom mobile banking application. Testers are provided full access to the code repository, database schemas, and API documentation to identify flaws like hardcoded secrets, cryptographic misconfigurations, or insecure API endpoints. ] } + +#let tlpAppendix() = { + [ + == Appendix: Traffic Light Protocol + + The Traffic Light Protocol (TLP) is a standardised system designed to accelerate collaborative response to security incidents by clarifying sharing boundaries for sensitive information. Information flows from an information source (e.g., a pentesting team) to recipients (e.g., clients or partners), with TLP labels governing permissible dissemination. The TLP labels standardised by FIRST#footnote("https://www.first.org/tlp/") are *RED*, *AMBER* and *AMBER+STRICT*, *GREEN*, and *CLEAR*. + + === TLP Label #helper.tlpLabel("RED") + + TLP:RED means _for the eyes of individual recipients only._ + The purpose is to protect highly sensitive information where unauthorized disclosure risks privacy, reputation, or operations. + Sharing is strictly prohibited outside the recipient - even within the recipients organisation. + + For example: an unauthenticated RCE vulnerability in a payment gateway API is classified TLP:RED. Sharing this internally (e.g., within a client’s incident response team or development team) is allowed; sharing anywhere else violates the classification. + + === TLP Label #helper.tlpLabel("AMBER") and #helper.tlpLabel("AMBER+STRICT") + + TLP:AMBER limits sharing to the recipient’s organization and its clients on a need-to-know basis. TLP:AMBER+STRICT restricts this further to the organisation, excluding clients. + The purpose is to allow collaboration with controlled exposure. Recipients may share with their own organization (and clients or partners if not using AMBER+STRICT), but must not share publicly or with non-authorized third parties. + + For example: a session fixation flaw in a client’s SaaS platform is TLP:AMBER. Their security team may share with their provider for patching, but cannot share it with unaffiliated parties. + + === TLP Label #helper.tlpLabel("GREEN") + + TLP:GREEN means _Restricted to the recipient’s community; not public._ + The purpose is to share awareness within a trusted community without public risk. + This allows recipients to share it with peers and partners within their defined community. + + For example: a misconfigured AWS S3 bucket exposing anonymized test data is TLP:GREEN. The testing team may share this within the cybersecurity community (e.g., via ISACs or industry forums) to improve collective awareness, but cannot publish it on the internet. + + === TLP Label #helper.tlpLabel("CLEAR") + + TLP:CLEAR means _No restrictions on disclosure._ + The purpose is to publicly share low-risk findings with no foreseeable misuse or patched vulnerabilities for transparency. + While sharing is unrestricted, the information may still be subject e.g. to copyright rules like attribution. + + For example: a server running an outdated but non-vulnerable SSL/TLS library qualifies as TLP:CLEAR. The testing team may publish this in a blog post to demonstrate tooling for automatic detection and general security practice. + ] +} \ No newline at end of file