SEC2-064: Reference notifier's test() echoes the OSError text, server-side path included, to the account holder #13

Closed
opened 2026-10-17 10:39:56 +00:00 by tiagoagueda · 0 comments
Owner

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

Severity: Informational · Category: Data Exposure · Reference: CWE-209 (Generation of Error Message Containing Sensitive Information); OWASP A04:2021 (Insecure Design)

Location:

  • src/postulo_helloworld/notifier.py:154-157

Issue

# notifier.py:154-157
except OSError as error:
    return TestResult(
        False, str(_("Could not write to the file: %(error)s")) % {"error": error}
    )

str(OSError) carries the filename, as in [Errno 13] Permission denied: '/srv/postulo/data/helloworld/x.log'. The person who pressed Test reads where the operator
keeps the directory, which file_for() takes pains to keep out of their hands. In a reference
plugin that others copy, this shape (%(error)s with the raw exception) is what gets copied.

Impact

Disclosure of a server path to a signed-in person. No further reach.

Fix

{"error": error.strerror or type(error).__name__}, so the reason is shown without the path.

Done when test_a_directory_that_cannot_be_written_to_fails_the_test_button_in_words raises an
error that carries a filename, PermissionError(13, "Permission denied", str(directory / "hello.log")) (the current PermissionError("read-only file system") has none), and asserts
str(directory) not in result.message.

Found on 2026-10-16 in a read-only security review of `postulo-helloworld` at `6afab68`, checked by a second, independent pass. **Severity:** Informational · **Category:** Data Exposure · **Reference:** CWE-209 (Generation of Error Message Containing Sensitive Information); OWASP A04:2021 (Insecure Design) **Location:** - `src/postulo_helloworld/notifier.py:154-157` ## Issue ```python # notifier.py:154-157 except OSError as error: return TestResult( False, str(_("Could not write to the file: %(error)s")) % {"error": error} ) ``` `str(OSError)` carries the filename, as in `[Errno 13] Permission denied: '/srv/postulo/data/helloworld/x.log'`. The person who pressed *Test* reads where the operator keeps the directory, which `file_for()` takes pains to keep out of their hands. In a reference plugin that others copy, this shape (`%(error)s` with the raw exception) is what gets copied. ## Impact Disclosure of a server path to a signed-in person. No further reach. ## Fix `{"error": error.strerror or type(error).__name__}`, so the reason is shown without the path. Done when `test_a_directory_that_cannot_be_written_to_fails_the_test_button_in_words` raises an error that carries a filename, `PermissionError(13, "Permission denied", str(directory / "hello.log"))` (the current `PermissionError("read-only file system")` has none), and asserts `str(directory) not in result.message`.
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-helloworld#13
No description provided.