Skip to content
Open
10 changes: 10 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@
**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-02 - Fix Null Byte Injection in File Validation
**Vulnerability:** File extension validation was vulnerable to null byte injection (`\u0000`) in filenames (e.g. `malicious.exe\0.png`), potentially bypassing format restrictions.
**Learning:** Checking the extension using `lastIndexOf('.')` after the null byte might allow harmful files to bypass the blocklist because backend file systems or execution contexts could interpret the filename up to the null byte.
**Prevention:** Always validate input file names for null bytes and explicitly reject them before proceeding with extension parsing.

## 2026-07-07 - Upgrade Dependency Or Exclude Vulnerable Modules
**Vulnerability:** `org.bouncycastle:bcprov-jdk18on` has a CRITICAL CVE (CVE-2025-14813) that causes the trivy-fs job to fail.
**Learning:** BouncyCastle modules were included as transitive dependencies via `tika-parsers-standard-package`.
**Prevention:** To satisfy trivy security scans, vulnerable transitive dependencies should be excluded in `pom.xml` if they are not necessary or upgraded to a secure version.
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-package</artifactId>
<version>3.2.2</version>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcjmail-jdk18on</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcutil-jdk18on</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public void validateOrThrow(MultipartFile file, PolicyOverrideRequest overrideRe
}

String fileName = file.getOriginalFilename();
if (fileName != null && fileName.indexOf('\u0000') != -1) {
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