passbolt/passbolt_api · error · Cake\Core\Exception\CakeException
No OpenPGP marker found.
Error message
No OpenPGP marker found.
What it means
getGpgMarker() extracts the ASCII-armored OpenPGP marker (the text after '-----BEGIN ', e.g. 'PGP PRIVATE KEY BLOCK') with a regex. If no marker pattern matches or the capture group is missing, it throws a CakeException('No OpenPGP marker found.'). The input string is therefore not an ASCII-armored OpenPGP structure at all.
Solutions
- Validate the input starts with '-----BEGIN PGP' before calling, and reject it early with a user-friendly message.
- Ask users to export armored keys: `gpg --armor --export <fingerprint>` (produces .asc, not binary .gpg).
- Trim whitespace/BOM from the input; check for truncation if the string comes from a form or DB column.
- If you have binary key data, armor it first (enigmail/gpg --enarmor) rather than passing raw bytes.
Example fix
// before
$info = $this->getKeyInfo($armoredKey); // throws on non-armored input
// after
if (!is_string($armoredKey) || strpos($armoredKey, '-----BEGIN PGP') !== 0) {
throw new \InvalidArgumentException('Please provide an ASCII-armored key (BEGIN PGP ... block).');
}
$info = $this->getKeyInfo($armoredKey); Defensive patterns
Strategy: validation
Validate before calling
if (!is_string($armored) || preg_match('/-----BEGIN PGP [A-Z0-9 ]+-----/', $armored) !== 1) {
throw new \InvalidArgumentException('Input is not an ASCII-armored OpenPGP block.');
} Type guard
function isArmoredOpenPgp(mixed $input): bool {
return is_string($input) && strpos($input, '-----BEGIN PGP') !== false;
} Try / catch
try {
$marker = $backend->getKeyInfo($armored);
} catch (\Cake\Core\Exception\CakeException $e) {
if ($e->getMessage() === 'No OpenPGP marker found.') {
// surface 'please paste the full armored key including BEGIN/END lines'
}
throw $e;
} Prevention
- Validate user-provided keys client-side for the BEGIN/END armor lines before submitting.
- Reject binary .gpg uploads; require .asc armored exports.
- Beware input truncation: check the string ends with the expected END line.
When it happens
Trigger: Called (directly or via assertGpgMarker / isParsableArmoredSignedMessage / getKeyInfo / getMessageInfo) with a string containing no '-(BEGIN )*([A-Z0-9 ]+)-' match: empty string, plain text, binary key data, or an armored block whose header is mangled (e.g. 'BEGIN PGP' without dashes).
Common situations: Users pasting a key without the BEGIN/END armor lines; uploading a binary .gpg file instead of an armored .asc; form input truncated by length limits cutting off the header; whitespace/encoding mangling from copy-paste.
Related errors
- A valid OpenPGP key must be provided.
- A valid OpenPGP key must be provided.
- Could not save the account recovery private key.
- Could not validate key revocation.
- Could not validate message data.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/d5af11c0b7b257cf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Utility/OpenPGP/Traits/OpenPGPBackendArmoredParseTrait.php:34
*/
namespace App\Utility\OpenPGP\Traits;
use Cake\Core\Exception\CakeException;
trait OpenPGPBackendArmoredParseTrait
{
/**
* Get the gpg marker.
*
* @param string $armored ASCII armored gpg data
* @return mixed
* @throws \Cake\Core\Exception\CakeException
*/
protected function getGpgMarker(string $armored): mixed
{
$isMarker = preg_match('/-(BEGIN )*([A-Z0-9 ]+)-/', $armored, $values);
if (!$isMarker || !isset($values[2])) {
throw new CakeException(__('No OpenPGP marker found.'));
}
return $values[2];
}
/**
* Forked from OpenPGP::unarmor
* Fail if key doesn't contain CRC instead of triggering php error
*
* @param string $text key
* @param string $header header
* @return string|false
*/
private function unarmor(string $text, string $header = 'PGP PUBLIC KEY BLOCK'): false|string
{
// @codingStandardsIgnoreStart
$header = \OpenPGP::header($header);
$text = str_replace(["\r\n", "\r"], ["\n", ''], $text);View on GitHub (pinned to 31c1bbc10f)