{"record":{"id":"d36ac640a7a6082d","repo":"SonarSource/sonarqube","slug":"can-get-file-filename","errorCode":null,"errorMessage":"Can get file ${filename}","messagePattern":"Can get file (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":500,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/BatchIndex.java","lineNumber":94,"sourceCode":"\n  @Override\n  public void stop() {\n    // Nothing to do\n  }\n\n  String getIndex() {\n    return index;\n  }\n\n  File getFile(String filename) {\n    try {\n      File input = new File(batchDir, filename);\n      if (!FilenameUtils.directoryContains(batchDir.getCanonicalPath(), input.getCanonicalPath()) || !input.exists()) {\n        throw new NotFoundException(\"Bad filename: \" + filename);\n      }\n      return input;\n    } catch (IOException e) {\n      throw new IllegalStateException(\"Can get file \" + filename, e);\n    }\n  }\n}\n","sourceCodeStart":76,"sourceCodeEnd":98,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/BatchIndex.java#L76-L98","documentation":"BatchIndex.getFile resolves a scanner-provided filename inside the batch working directory and returns it as a File. If the resolved path escapes batchDir (path traversal check via FilenameUtils.directoryContains) or does not exist, a NotFoundException is thrown; if resolving canonical paths or checking existence throws an IOException, it is wrapped in this IllegalStateException. It guards the batch download endpoint against bad or malicious filenames.","triggerScenarios":"GET of a batch/file resource where the filename contains path separators or '..' so canonicalization fails mid-check, or the underlying file is deleted/renamed between the exists() check and canonical path computation causing an IOException.","commonSituations":"Scanner caching a file URL and the server's batch directory being cleaned up (temp cleanup, restart) before download; corrupted or hand-crafted scanner requests with traversal-style filenames; symlinked batch directories breaking canonical-path containment.","solutions":["Re-run the scanner so it re-requests a freshly generated batch manifest","Check the file still exists in the batch directory and that batchDir/files were not pruned","Verify the filename in the request has no path separators or '..' segments","Ensure the batch directory is not a symlink and no canonicalization mismatch (different mounts, case-insensitive FS)"],"exampleFix":"// before\nFile input = new File(batchDir, filename);\n// after\nFile input = new File(batchDir, new File(filename).getName()); // strip path components before resolution","handlingStrategy":"validation","validationCode":"if (filename.contains(\"/\") || filename.contains(\"..\")) throw new IllegalArgumentException(\"bad filename\");\n// also ensure the file was listed in the current batch manifest before requesting it","typeGuard":null,"tryCatchPattern":"try { File f = batchIndex.getFile(filename); } catch (NotFoundException e) { reRequestBatch(); }","preventionTips":["Never persist batch file URLs across server restarts or long waits","Sanitize filename inputs to a bare name","Keep batch directories alive for the duration of the scan"],"tags":["java","sonarqube","file-not-found","path-traversal"],"backgroundTag":"file-not-found","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}