diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..ae567b1
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,23 @@
+# SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# Local sandbox setup for nfse-php smoke tests
+# Copy to .env.local and fill the secret values.
+
+# Full HEAD URL for sandbox mTLS smoke test
+# Example:
+# NFSE_HEAD_URL="https://adn.producaorestrita.nfse.gov.br/dps/00000000000000000000000000000000000000000000"
+NFSE_HEAD_URL="https://adn.producaorestrita.nfse.gov.br/dps/CHANGE_ME"
+
+# PFX certificate used for mTLS (local file, never commit)
+NFSE_MTLS_PFX_PATH=".secrets/pfx/2025-LibreCode.pfx"
+NFSE_MTLS_PFX_PASSWORD="CHANGE_ME"
+
+# Optional: set to 1 to print TLS handshake details
+NFSE_CURL_VERBOSE=0
+
+# Optional OpenBao/Vault settings (if needed by local app wiring)
+VAULT_ADDR="http://openbao:8200"
+VAULT_TOKEN=""
+VAULT_ROLE_ID=""
+VAULT_SECRET_ID=""
diff --git a/.gitignore b/.gitignore
index 6e94e98..c81ed4b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@
/.php-cs-fixer.cache
/.phpunit.cache
/composer.lock
+/.env
+/.env.local
+/.secrets/
diff --git a/tests/Integration/Http/SandboxMtlsHeadTest.php b/tests/Integration/Http/SandboxMtlsHeadTest.php
new file mode 100644
index 0000000..33052c4
--- /dev/null
+++ b/tests/Integration/Http/SandboxMtlsHeadTest.php
@@ -0,0 +1,67 @@
+put('pfx/' . $cnpj, [
+ 'pfx_path' => $pfxPath,
+ 'password' => $pfxPassword,
+ ]);
+
+ $signer = new DpsSigner($store);
+ $xml = 'abc';
+
+ try {
+ $signed = $signer->sign($xml, $cnpj);
+ } catch (PfxImportException $e) {
+ $message = strtolower($e->getMessage());
+
+ // Local OpenSSL runtime may not support legacy PKCS#12 algorithms.
+ if (str_contains($message, 'digital envelope routines') || str_contains($message, 'asn1 encoding routines')) {
+ self::markTestSkipped('Local OpenSSL runtime cannot import this PFX format.');
+ }
+
+ throw $e;
+ }
+
+ self::assertStringContainsString('