SEC2-023: The threat model says a theme is "never" handed a referee's entry or contact, but the template context carries the whole CV #965

Closed
opened 2026-10-17 10:38:33 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-10-16 in a read-only security review of postulo at 56fc9d531, checked by a second, independent pass.

Severity: Informational · Category: Configuration · Reference: CWE-1059 (Insufficient Technical Documentation); OWASP A04:2021 (Insecure Design)

Location:

  • docs/THREAT-MODEL.md:78-79 (the referee paragraph's promise about themes)
  • src/postulo/documents/rendering.py:488 ("cv": cv in the theme context) and :825 ("letter": letter)
  • src/postulo/documents/rendering.py:170-225 (Referee, referee_for)

Issue

THREAT-MODEL.md promises: "The renderer hands a theme a read-only value built under those two rules and never the entry or the contact, so a theme from a plugin cannot step round them." build_sections does exactly that for sections: a reference becomes a Referee value with the email and number blank unless agreed and chosen. But the same context also passes the model instance:

        return render_to_string(
            themes.template_for(cv.theme, cv.theme_kind),
            {
                "cv": cv,
                "sections": build_sections(cv),

Django templates follow relations, so a theme can reach each CV item's reference entry and its contact (address included, agreed or not) through cv, and the person's own profile fields the CV switched off. The shipped themes read only cv.headline, cv.summary, cv.show_eqf_level and cv.references_on_request from it. The letter context is the same, and also carries application and letter.owner. #820 recorded that plugin themes are handed full records, and the threat model's plugin row now says so ("a plugin theme is handed full records to draw (#820)"), which leaves the referee paragraph contradicting the plugin paragraph in the same document.

Impact

None beyond #820: a theme is installed by an administrator and trusted. The paragraph about referees overstates the guarantee.

Fix

Reword docs/THREAT-MODEL.md:78-79 to say that the shipped themes and the sections value obey the two rules, and that a theme from a plugin is handed the records and is trusted, as the plugin row says (#820). Handing themes a reduced read-only view of the CV and letter instead would be a change to the theme contract, which the open theme issues (#340, #341, #343) would have to be written against, and would still leave application and letter.owner in the letter context. Done when the sentence is changed; optionally, a registered test theme in tests/security/test_cv_prints.py that walks the CV's items gives whichever promise the document makes a test.

#820 (closed) - the general statement that plugin themes get full instances; this paragraph is the part it left contradicting it. #696 (closed) - wrote the referee paragraph. #340, #341, #343 (open) - theme work a reduced theme context would have to be designed with.

Found on 2026-10-16 in a read-only security review of `postulo` at `56fc9d531`, checked by a second, independent pass. **Severity:** Informational · **Category:** Configuration · **Reference:** CWE-1059 (Insufficient Technical Documentation); OWASP A04:2021 (Insecure Design) **Location:** - `docs/THREAT-MODEL.md:78-79` (the referee paragraph's promise about themes) - `src/postulo/documents/rendering.py:488` (`"cv": cv` in the theme context) and `:825` (`"letter": letter`) - `src/postulo/documents/rendering.py:170-225` (`Referee`, `referee_for`) ## Issue `THREAT-MODEL.md` promises: "The renderer hands a theme a read-only value built under those two rules and never the entry or the contact, so a theme from a plugin cannot step round them." `build_sections` does exactly that for `sections`: a reference becomes a `Referee` value with the email and number blank unless agreed and chosen. But the same context also passes the model instance: ```python return render_to_string( themes.template_for(cv.theme, cv.theme_kind), { "cv": cv, "sections": build_sections(cv), ``` Django templates follow relations, so a theme can reach each CV item's reference entry and its contact (address included, agreed or not) through `cv`, and the person's own profile fields the CV switched off. The shipped themes read only `cv.headline`, `cv.summary`, `cv.show_eqf_level` and `cv.references_on_request` from it. The letter context is the same, and also carries `application` and `letter.owner`. #820 recorded that plugin themes are handed full records, and the threat model's plugin row now says so ("a plugin theme is handed full records to draw (#820)"), which leaves the referee paragraph contradicting the plugin paragraph in the same document. ## Impact None beyond #820: a theme is installed by an administrator and trusted. The paragraph about referees overstates the guarantee. ## Fix Reword `docs/THREAT-MODEL.md:78-79` to say that the shipped themes and the `sections` value obey the two rules, and that a theme from a plugin is handed the records and is trusted, as the plugin row says (#820). Handing themes a reduced read-only view of the CV and letter instead would be a change to the theme contract, which the open theme issues (#340, #341, #343) would have to be written against, and would still leave `application` and `letter.owner` in the letter context. Done when the sentence is changed; optionally, a registered test theme in `tests/security/test_cv_prints.py` that walks the CV's items gives whichever promise the document makes a test. ## Related #820 (closed) - the general statement that plugin themes get full instances; this paragraph is the part it left contradicting it. #696 (closed) - wrote the referee paragraph. #340, #341, #343 (open) - theme work a reduced theme context would have to be designed with.
tiagoagueda added this to the 1.0.0 milestone 2026-10-17 10:38:34 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#965
No description provided.