{"record":{"id":"4a43dea308491aea","repo":"symfony/http-kernel","slug":"the-profiler-token-s-is-invalid-only-letters-digits-dashes","errorCode":null,"errorMessage":"The profiler token \"%s\" is invalid: only letters, digits, dashes and underscores are allowed.","messagePattern":"The profiler token \"(.+?)\" is invalid: only letters, digits, dashes and underscores are allowed\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Profiler/FileProfilerStorage.php","lineNumber":217,"sourceCode":"            fclose($file);\n\n            if (1 === random_int(1, 10)) {\n                $this->removeExpiredProfiles();\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Gets filename to store data, associated to the token.\n     *\n     * @throws \\InvalidArgumentException when the token cannot be used as a file name\n     */\n    protected function getFilename(string $token): string\n    {\n        if (!self::isValidToken($token)) {\n            throw new \\InvalidArgumentException(\\sprintf('The profiler token \"%s\" is invalid: only letters, digits, dashes and underscores are allowed.', $token));\n        }\n\n        // Uses 4 last characters, because first are mostly the same.\n        $folderA = substr($token, -2, 2);\n        $folderB = substr($token, -4, 2);\n\n        return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token;\n    }\n\n    /**\n     * Gets the index filename.\n     */\n    protected function getIndexFilename(): string\n    {\n        return $this->folder.'/index.csv';\n    }\n\n    /**","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/symfony/http-kernel/blob/aa3a39d7286a62cdfea98f0e69c651a3da6e36cf/Profiler/FileProfilerStorage.php#L199-L235","documentation":"FileProfilerStorage::getFilename() validates that a profile token can safely be used as a file name and throws InvalidArgumentException for anything outside letters, digits, dashes and underscores. This prevents path traversal and malformed paths, since tokens are embedded directly into directory and file names.","triggerScenarios":"Calling doRead($token) or write($profile) with an invalid token, or removeExpiredProfiles when a stored token contains other characters (e.g. an empty string, slashes, or ':' / '.' from a custom generator).","commonSituations":"Passing user-supplied token values from query params straight into loadProfile/read, custom token generators emitting characters like ':' or '/', corrupted or empty token values read from another storage backend.","solutions":["Validate the token before calling the storage: use FileProfilerStorage::isValidToken($token) or check it against /^[A-Za-z0-9_-]+$/.","If loading from user input, reject invalid values with a 400 response instead of passing them to the storage.","Fix custom token generation to emit only alphanumerics plus '-' and '_' (e.g. the substr(bin2hex(random_bytes(...))) pattern used by Profiler).","Handle empty tokens explicitly before calling doRead()."],"exampleFix":"// before\n$profile = $storage->read($_GET['token']); // may contain '/', ':' etc.\n// after\n$token = $_GET['token'];\nif (!FileProfilerStorage::isValidToken($token)) {\n    throw new \\InvalidArgumentException('Invalid profiler token.');\n}\n$profile = $storage->read($token);","handlingStrategy":"validation","validationCode":"function isSafeProfilerToken(string $token): bool {\n    return preg_match('/^[A-Za-z0-9_-]{1,64}$/', $token) === 1;\n}\n// call before read()/write(); or use FileProfilerStorage::isValidToken($token)","typeGuard":"function validToken(?string $token): ?string {\n    return ($token !== null && preg_match('/^[A-Za-z0-9_-]+$/', $token) === 1) ? $token : null;\n}","tryCatchPattern":"try {\n    $profile = $storage->read($token);\n} catch (\\InvalidArgumentException $e) {\n    $profile = null; // treat as bad request\n    http_response_code(400);\n}","preventionTips":["Never pass raw user input as a profiler token without validating it.","Use the library's own token generator (Profiler) instead of custom token formats.","Run isValidToken() in code paths shared between storage backends.","Treat profiler token lookups as untrusted input to guard against path traversal."],"tags":["validation","symfony","profiler","input-validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"aa3a39d7286a62cdfea98f0e69c651a3da6e36cf","analyzedAt":"2026-09-13T18:03:36.509Z","contentChangedAt":"2026-09-13T18:03:36.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}