Fix command injection when passing bash commands into the dns provider configuration

- Use built in node functions to write the file
- And to delete the file
This commit is contained in:
Jamie Curnow 2024-07-01 16:08:01 +10:00
parent 120d50e5c0
commit 99cce7e2b0
No known key found for this signature in database
GPG Key ID: FFBB624C43388E9E

View File

@ -861,9 +861,8 @@ const internalCertificate = {
logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id; const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
// Escape single quotes and backslashes fs.mkdirSync('/etc/letsencrypt/credentials', { recursive: true });
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\'); fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, {mode: 0o600});
const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
// Whether the plugin has a --<name>-credentials argument // Whether the plugin has a --<name>-credentials argument
const hasConfigArg = certificate.meta.dns_provider !== 'route53'; const hasConfigArg = certificate.meta.dns_provider !== 'route53';
@ -898,17 +897,15 @@ const internalCertificate = {
mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore'; mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
} }
logger.info('Command:', `${credentialsCmd} && && ${mainCmd}`); logger.info('Command:', mainCmd);
try { try {
await utils.exec(credentialsCmd);
const result = await utils.exec(mainCmd); const result = await utils.exec(mainCmd);
logger.info(result); logger.info(result);
return result; return result;
} catch (err) { } catch (err) {
// Don't fail if file does not exist // Don't fail if file does not exist, so no need for action in the callback
const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`; fs.unlink(credentialsLocation, () => {});
await utils.exec(delete_credentialsCmd);
throw err; throw err;
} }
}, },