Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@
**Vulnerability:** Untrusted paths from API responses were directly assigned to `a.href` and used in `iframe` generation, which allows execution of malicious URIs like `javascript:` or `data:`.
**Learning:** Even when avoiding `innerHTML`, directly setting URL-like strings to DOM attributes without protocol validation introduces XSS vectors. The payload can be executed when the link is clicked or the iframe is loaded.
**Prevention:** Implement an `isSafeUrl` verification function to ensure the protocol is strictly `http:` or `https:` (using `new URL()`) before assigning untrusted inputs to DOM attributes like `href` or `src`.

## 2026-07-08 - Prevent Null Byte Injection in File Validation
**Vulnerability:** The document validation service relied on the original filename without verifying the presence of null bytes (`\u0000`). This allows attackers to bypass file extension checks via truncation (e.g., `malicious.hwp\u0000.pdf`).
**Learning:** Checking the file extension using standard string operations can be bypassed if the underlying system API (like a C-based filesystem or a library handling byte arrays) truncates the string at the first null byte.
**Prevention:** Explicitly check for the presence of null bytes (`\u0000`) in the filename as early as possible and throw an exception to reject the input entirely, rather than attempting to sanitize it.
25 changes: 25 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@
<pdfjs.dist.version>4.10.38</pdfjs.dist.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.84</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.84</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcutil-jdk18on</artifactId>
<version>1.84</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcjmail-jdk18on</artifactId>
<version>1.84</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,18 @@ public void validateOrThrow(MultipartFile file) {
* {@inheritDoc}
*/
@Override
public void validateOrThrow(MultipartFile file, PolicyOverrideRequest overrideRequest) {
public void validateOrThrow(final MultipartFile file, final PolicyOverrideRequest overrideRequest) {
if (file == null || file.isEmpty()) {
throw new IllegalArgumentException("File is required.");
}

String fileName = file.getOriginalFilename();
if (fileName != null && fileName.indexOf('\u0000') >= 0) {
throw new IllegalArgumentException(
"File name contains invalid characters."
);
}

String extension = extensionOf(fileName);
if (extension.isEmpty()) {
throw new IllegalArgumentException("File extension is required.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,22 @@ void rejectsMultipartWithNullOriginalFilename() {
assertEquals("File extension is required.", ex.getMessage());
}

@Test
void rejectsFilenameWithNullByte() {
ConversionProperties conversionProperties = new ConversionProperties();
conversionProperties.setBlockedExtensions(Set.of("hwp", "hwpx"));
DefaultDocumentValidationService validationService = new DefaultDocumentValidationService(conversionProperties);

IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
() -> validationService.validateOrThrow(
new MockMultipartFile("file", "contract.hwp\u0000.pdf", "application/octet-stream", new byte[] {1})
)
);

assertEquals("File name contains invalid characters.", ex.getMessage());
}

@Test
void rejectsFilenameEndingWithDot() {
ConversionProperties conversionProperties = new ConversionProperties();
Expand Down
Loading