Skip to content

Security Features

Valicomb is designed with security as a core principle. This guide covers the built-in security features and best practices for secure validation.

Regular Expression Denial of Service (ReDoS) attacks exploit inefficient regex patterns that cause catastrophic backtracking.

The regex rule includes automatic protection by setting strict execution limits:

use Frostybee\Valicomb\Validator;
$v = new Validator(['field' => 'aaaaaaaaaaaa!']);
// This throws RuntimeException when backtrack limit is exhausted
$v->rule('regex', 'field', '/^(a+)+$/');
$v->validate(); // RuntimeException: Regex execution failed: Backtrack limit exhausted

The protection works by:

  1. Setting pcre.backtrack_limit and pcre.recursion_limit to 1000 during execution
  2. Throwing a RuntimeException if limits are exceeded
  3. Restoring original INI settings after execution

Good patterns:

$v->rule('regex', 'field', '/^[a-zA-Z0-9]+$/'); // Simple character class
$v->rule('regex', 'field', '/^\d{3}-\d{4}$/'); // Fixed quantifiers
$v->rule('regex', 'field', '/^[A-Z]{2}\d{6}$/'); // Bounded patterns

Dangerous patterns to avoid:

// Nested quantifiers
'/^(a+)+$/'
'/^(a*)*$/'
'/^(a+)*$/'
// Overlapping groups
'/^(a|aa)+$/'
// Unbounded repetition with alternatives
'/^([a-zA-Z]+)*$/'

PHP’s type juggling can lead to security vulnerabilities. Valicomb uses strict comparisons throughout.

All comparisons use === to prevent type juggling:

$v = new Validator([
'field1' => '0e123456', // "Scientific notation" string
'field2' => '0e789012'
]);
// In PHP, these would loosely equal 0 == 0
// Valicomb uses strict comparison, so this correctly returns false
$v->rule('equals', 'field1', 'field2');

The boolean rule accepts only explicit boolean values:

$v = new Validator(['active' => '1']);
$v->rule('boolean', 'active'); // true - '1' is accepted
$v = new Validator(['active' => 'yes']);
$v->rule('boolean', 'active'); // false - 'yes' is not a boolean
// Use 'accepted' for checkbox-style values
$v->rule('accepted', 'terms'); // Accepts 'yes', 'on', 1, '1', true

URL validation includes multiple security checks.

URLs must start with allowed protocols - not just contain them:

// FAIL - protocol not at start (potential redirect attack)
$v = new Validator(['url' => 'evil.com?redirect=http://trusted.com']);
$v->rule('url', 'url'); // false
// PASS - proper URL with protocol at start
$v = new Validator(['url' => 'https://trusted.com']);
$v->rule('url', 'url'); // true

Only safe protocols are allowed by default:

  • http://
  • https://
  • ftp://

Dangerous protocols like javascript: and data: are not allowed.


Language file loading validates against directory traversal attacks using multiple layers of protection:

// Path components are stripped, then validated against whitelist
new Validator([], [], '../../etc/passwd');
// Throws: InvalidArgumentException: Invalid language 'passwd'. Allowed: ar, cs, da, ...
new Validator([], [], '../../../evil');
// Throws: InvalidArgumentException: Invalid language 'evil'. Allowed: ar, cs, da, ...
  1. basename() strips directory traversal attempts (../../etc/passwdpasswd)
  2. Result is validated against a strict whitelist of allowed language codes
  3. realpath() normalizes the language directory path

Only whitelisted language codes are accepted:

  • Allowed: ar, cs, da, de, en, es, fa, fi, fr, hu, id, it, ja, nl, no, pl, pt, ru, sv, tr, uk, zh
  • Rejected: Any other value, including path traversal attempts

Email validation includes comprehensive security measures:

  • Maximum total length: 254 characters
  • Maximum local part (before @): 64 characters
  • Maximum domain part (after @): 255 characters

Dangerous characters that could be used for injection are rejected:

  • Null bytes
  • Newlines
  • Carriage returns
  • Invalid control characters
$v = new Validator(['email' => 'user@example.com']);
$v->rule('email', 'email');
// These would fail:
// - "user\0@example.com" (null byte)
// - "user\n@example.com" (newline injection)
// - Excessively long emails

The integer validation properly handles all numeric formats:

$v = new Validator(['num' => '1000']);
$v->rule('integer', 'num'); // true - works with multi-digit numbers
$v = new Validator(['num' => '1000']);
$v->rule('integer', 'num', true); // Strict mode - proper numeric form

Strict mode rejects redundant formatting:

// Strict mode rejects redundant plus sign
$v = new Validator(['num' => '+27']);
$v->rule('integer', 'num', true); // false
// Negative numbers are accepted
$v = new Validator(['num' => '-27']);
$v->rule('integer', 'num', true); // true

When BCMath is available, numeric comparisons use high-precision arithmetic:

// With BCMath, this comparison is precise
$v = new Validator(['price' => '0.1']);
$v->rule('min', 'price', 0.1); // Correctly returns true
// Without BCMath, floating-point issues could occur

// Never trust user input
$v = new Validator($_POST);
$v->rule('required', ['email', 'password']);
$v->rule('email', 'email');
$v->rule('lengthMin', 'password', 8);
// Specific is better than generic
$v->rule('email', 'email'); // Good - validates email format
$v->rule('lengthMax', 'email', 5); // Bad - just checks length
if ($v->validate()) {
// Only use data after validation passes
$email = $v->data()['email'];
}
if (!$v->validate()) {
// Return user-friendly errors
$errors = $v->errors();
// Log detailed errors internally
error_log(json_encode($errors));
}
// Whitelist allowed values
$v->rule('in', 'status', ['active', 'inactive', 'pending']);
// Rather than trying to block bad values

Valicomb validates data, not files. For file uploads:

  • Validate MIME types server-side
  • Use a dedicated file validation library
  • Never trust client-provided file extensions

If you discover a security vulnerability in Valicomb:

  1. Do NOT create a public GitHub issue
  2. Create a private security advisory on GitHub
  3. Or email the maintainer directly

Provide details about:

  • The vulnerability
  • Steps to reproduce
  • Potential impact