| name | secure-microsoft-excel-validation |
| description | Generate secure microsoft excel file validation code. Enforces secure generation of code validating a microsoft excel file. Invoke when writing any microsoft excel file validation related code. |
| allowed-tools | Read Grep Glob |
| metadata | {"category":"security"} |
Secure Microsoft Excel File Validation Code Generation Rules
Apply all rules below when generating or reviewing any code related to validation of a Microsoft Excel file.
1. Microsoft Excel file validation (CRITICAL)
- ALWAYS ensure that the file is a real Microsoft Excel file.
- ALWAYS ensure that the file use the standard named
Office Open XML.
- ALWAYS ensure that the file use the file type named
XLSX.
- ALWAYS ensure that the file has a single extension and is
xlsx.
- ALWAYS ensure that the file size does not exceed 5 megabytes before opening or parsing it.
- ALWAYS ensure that the total uncompressed size of all ZIP entries does not exceed 50 megabytes before opening or parsing it.
- ALWAYS ensure that the file has no Visual Basic for Application (VBA) macros.
- ALWAYS ensure that the file has no Object Linking and Embedding (OLE) package.
- ALWAYS ensure that the file has no external data connections.
- ALWAYS ensure that the file has no external links.
- ALWAYS ensure that the file has no Dynamic Data Exchange (DDE) formula in cell content.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
public class UnsafeReadExcelFile {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("spreadsheet.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
XSSFSheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
System.out.print(cell + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
public class SafeExcelFileReader {
public static void main(String[] args) {
try {
File file = new File("spreadsheet.xlsx");
String name = file.getName();
int dotCount = name.length() - name.replace(".", "").length();
if (dotCount != 1) {
throw new SecurityException("File must have exactly one extension. Found: " + name);
}
if (!name.toLowerCase().endsWith(".xlsx")) {
throw new SecurityException("File extension must be '.xlsx'. Found: " + name);
}
long maxSizeBytes = 5L * 1024 * 1024;
if (file.length() > maxSizeBytes) {
throw new SecurityException("File size exceeds the maximum allowed size of 5 MB. Found: " + file.length() + " bytes.");
}
try (FileInputStream fis = new FileInputStream(file)) {
byte[] header = new byte[4];
int bytesRead = fis.read(header);
if (bytesRead < 4 || header[0] != 0x50 || header[1] != 0x4B || header[2] != 0x03 || header[3] != 0x04) {
throw new SecurityException("File is not a valid Office Open XML (OOXML/ZIP) file. Magic bytes do not match PK\\x03\\x04.");
}
}
long maxUncompressedBytes = 50L * 1024 * 1024;
long totalUncompressedSize = 0;
byte[] drainBuffer = new byte[8192];
try (java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(new java.io.BufferedInputStream(new FileInputStream(file)))) {
java.util.zip.ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
int bytesRead;
while ((bytesRead = zis.read(drainBuffer)) != -1) {
totalUncompressedSize += bytesRead;
if (totalUncompressedSize > maxUncompressedBytes) {
throw new SecurityException("File total uncompressed size exceeds the maximum allowed size of 50 MB. Possible ZIP bomb detected.");
}
}
zis.closeEntry();
}
}
String oleObjectUri = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
String activeXUri = "http://schemas.microsoft.com/office/2006/relationships/activeX";
try (OPCPackage pkg = OPCPackage.open(file)) {
if (pkg.getPartsByName(java.util.regex.Pattern.compile("/xl/workbook\\.xml")).isEmpty()) {
throw new SecurityException("File does not contain 'xl/workbook.xml'. It is not a valid XLSX file.");
}
if (!pkg.getPartsByName(java.util.regex.Pattern.compile("(?i)/xl/vbaProject\\.bin")).isEmpty()) {
throw new SecurityException("File contains a VBA macro project (vbaProject.bin). Macro-enabled workbooks (XLSM) are not allowed.");
}
if (!pkg.getPartsByName(java.util.regex.Pattern.compile("(?i)/xl/connections\\.xml")).isEmpty()) {
throw new SecurityException("File contains external data connections (connections.xml). External data connections are not allowed.");
}
if (!pkg.getPartsByName(java.util.regex.Pattern.compile("(?i)/xl/externalLinks/.*")).isEmpty()) {
throw new SecurityException("File contains external links (externalLinks/). External links are not allowed.");
}
for (PackagePart part : pkg.getParts()) {
for (PackageRelationship rel : part.getRelationships()) {
String relType = rel.getRelationshipType();
if (relType != null) {
String lower = relType.toLowerCase();
if (lower.startsWith(oleObjectUri.toLowerCase()) || lower.startsWith(activeXUri.toLowerCase())) {
throw new SecurityException("File contains an embedded OLE object in part: " + part.getPartName() + ". OLE packages are not allowed.");
}
}
}
}
java.util.List<PackagePart> sheetParts = pkg.getPartsByName(java.util.regex.Pattern.compile("/xl/worksheets/sheet[0-9]+\\.xml"));
java.util.regex.Pattern ddePattern = java.util.regex.Pattern.compile("\\bDDEAUTO\\b|\\bDDE\\b");
for (PackagePart sheetPart : sheetParts) {
try (java.io.InputStream sheetIs = sheetPart.getInputStream()) {
String sheetXml = new String(sheetIs.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8).toUpperCase();
if (ddePattern.matcher(sheetXml).find()) {
throw new SecurityException("File contains a DDE formula in sheet: " + sheetPart.getPartName() + ". DDE formulas are not allowed.");
}
}
}
}
try (FileInputStream fis = new FileInputStream(file);
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
XSSFSheet sheet = workbook.getSheetAt(i);
System.out.println("=== Sheet: " + sheet.getSheetName() + " ===");
for (Row row : sheet) {
for (Cell cell : row) {
System.out.print(cell + "\t");
}
System.out.println();
}
}
}
} catch (SecurityException e) {
System.err.println("Security validation failed: " + e.getMessage());
} catch (Exception e) {
System.err.println("Error reading file: " + e.getMessage());
}
}
}
2. Output Checklist
Before finalizing generated code, verify:
References