Security Notes

Security considerations for wpzylos-container.

Binding Security

Don't Bind User Input Directly

Never use user input to determine what class to instantiate:

// Bad: DANGEROUS: Remote code execution
$class = $_GET['service'];
$container->bind('service', $class);

// Good: Whitelist allowed classes
$allowed = [
    'json' => JsonFormatter::class,
    'xml' => XmlFormatter::class,
];
$type = $_GET['format'] ?? 'json';
if (isset($allowed[$type])) {
    $container->bind(Formatter::class, $allowed[$type]);
}

Validate Factory Closures

When factories come from configuration:

// Bad: Don't execute arbitrary callbacks
$factory = get_option('custom_factory');
$container->bind('service', $factory);

// Good: Use known, safe factories
$container->bind('service', function ($c) {
    $config = $c->get(Config::class);
    return new Service($config->get('service.option'));
});

Resolution Security

Scope Service Access

Don't expose the container globally:

// Bad: Global access allows bypassing authorization
global $container;

// Good: Inject only what's needed
class Controller
{
    public function __construct(
        private UserRepository $users,
        private Gate $gate
    ) {}
}

Immutable After Boot

Prevent rebinding after application boots:

class SecureContainer extends Container
{
    private bool $locked = false;

    public function lock(): void
    {
        $this->locked = true;
    }

    public function bind(string $abstract, $concrete = null): void
    {
        if ($this->locked) {
            throw new \RuntimeException('Container is locked');
        }
        parent::bind($abstract, $concrete);
    }
}