Dear debconf maintainers,
I would like to report an input-validation issue in debconf 1.5.92,
confirmed at runtime in a fresh debian:sid container.
Several debconf database driver initialization paths interpolate
attacker-influenced format or driver names into Perl eval STRING:
Debconf/DbDriver/File.pm
Debconf/DbDriver/Directory.pm
Debconf/DbDriver/Pipe.pm
Debconf/Db.pm
The affected values come from debconf database configuration, including
environment/config routes such as DEBCONF_DB_OVERRIDE, DEBCONF_DB_FALLBACK,
DEBCONF_DB_REPLACE, DEBCONF_SYSTEMRC, DPKG_ROOT, and ${VAR} substitution in
Config.pm.
A crafted format value can cause attacker-controlled Perl code to be
evaluated when the corresponding debconf database configuration is loaded.
Confirmed impact:
- Arbitrary code execution in the debconf-using Perl process that loads
attacker-influenced debconf database configuration.
- The code runs as the UID/EUID of that Perl process.
- Local privilege escalation is possible only when attacker-controlled
debconf environment/configuration crosses a privilege boundary into a
privileged debconf-using process.
This is not a remote vulnerability and does not become privilege escalation
on a default Debian system by itself. With sudo's default env_reset, the
relevant environment variables are dropped before the privileged process
runs.
Runtime validation:
- Confirmed in debian:sid with debconf 1.5.92.
- Nine trigger variants were tested.
- Before patch: benign marker files were created by the Perl process.
- After patch: all tested malicious format/driver names were rejected.
- Legitimate Format: 822 configuration still works.
- Legitimate ${VAR} substitution for non-Format fields still works.
Proposed fix:
The attached patch validates format and driver names before the eval sinks
using:
\A[A-Za-z0-9_]+\z
The patch touches:
Debconf/DbDriver/File.pm
Debconf/DbDriver/Directory.pm
Debconf/DbDriver/Pipe.pm
Debconf/Db.pm
Debconf/Config.pm is intentionally left unchanged. The ${VAR} substitution
path can still transport a malicious value into the stanza, but the value
is blocked at the eval sinks.
Public context:
I initially sent this to Debian Security and debconf-devel. Salvatore
Bonaccorso noted that debconf-devel is not private and asked me to file
this directly in the BTS for maintainer tracking:
https://alioth-lists.debian.net/pipermail/debconf-devel/2026-May/005526.html
Please let me know if you prefer a fixed allowlist of known Format/DbDriver
module names instead of the current character-class validation approach.
Best regards,
Jeremy Erazo
[image: Mailsuite] Email trackeado con Mailsuite · Darse de baja
<https://u.list-prefs.com/en/privacy/opt-out/unsubscribe/96fbe1d8a4d5ed9b87118e85e984a86b7313ffd6/420689cfb77e738ceec082be09a9bcf456e92a5f914b9285f9f16f628386013bfc77683b948bcfff21b78b66da3e9739451bd062d209c37330abf933b7c5d1ee>
09/05/26, 12:15:57 p.m.
[Please drop team@security from CCs in replies, for the reasons given
below.]
In general, debconf doesn't attempt to implement any kind of security
boundary, and an unprivileged user being able to control DEBCONF_*
environment variables would already be a significant problem on its own:
they would be able to substitute their own answers to debconf questions
asked by packages, which could have arbitrarily complex consequences.
Any arrangements that allow users to run debconf in privileged contexts
_must_ forbid them from setting those environment variables.
Therefore, I'm not inclined to treat poor validation of those
environment variables, which already must not be allowed to be set at
all by unprivileged users, as a security problem. I'm happy to treat it
as a quality-of-implementation problem, though.
things being equal, it's usually better to avoid the need for validation
in the first place; this is analogous to the well-known reasons that
it's better to avoid system()-style interfaces (where one has to
sanitize shell metacharacters first) in favour of things with an
execve()-style interface.
So, how about using this sort of construct (which I've tested lightly at
an interactive prompt, but not in any detail) instead of string eval?
use File::Spec;
my @parts = split /::/, $this->{format};
my $module = File::Spec->catfile('Debconf', 'Format', $this->{format});
eval { require "$module.pm"; };
Of course, that has a path traversal vulnerability: you could supply a
format beginning with "../../" and then load whatever module you like.
(Or add further "../" and potentially get anything on the system,
although this would be hard to do much with since you'd need something
with the ".pm" suffix.) So that becomes something like:
use File::Spec;
my @parts = split /::/, $this->{format};
my $module = File::Spec->catfile('Debconf', 'Format', $this->{format});
if ($module !~ m{\A[A-Za-z0-9/_]+\Z}) {
$this->error("Invalid plugin name: $this->{format}");
return;
}
eval { require "$module.pm"; };
Now, that's taken us right back to doing up-front validation, which I
just said I wanted to avoid! Still, I think it's worth avoiding string
eval on general principles anyway, so maybe this is worth the effort.
This is enough code that it would definitely need to go into a utility
module somewhere. There's no very obvious existing module that would
suit, but if the code were generalized a little bit then it could go
into a new Debconf::Plugin module. As well as the code your patch
already touches, this could potentially be used in
Debconf::AutoSelect::make_frontend and
Debconf::FrontEnd::_loadelementclass.
What do you think? If this is too much refactoring then I'm happy to do
it, but I thought I'd give you the opportunity.
Thanks,
Hi Colin,
Thank you again for the detailed guidance.
I took up your suggestion and prepared a revised patch that avoids string
eval for the dynamic debconf plugin-loading paths instead of only
validating immediately before the eval.
The patch introduces a small reusable Debconf::Plugin helper. It validates
the original plugin name before converting it into a module path, then
loads the resulting .pm file with require. I intentionally validate the
original name rather than only the constructed path, since validating the
path alone would still allow names containing / to become valid path
segments after catfile.
The patch currently covers the original Format/DbDriver paths as well as
the related frontend-loading paths you mentioned:
- Debconf::Db
- Debconf::DbDriver::{File,Directory,Pipe}
- Debconf::AutoSelect::make_frontend
- Debconf::FrontEnd::_loadelementclass
I also adjusted the helper contract so that Debconf::Plugin::load
consistently throws on both validation and require failures. This preserves
the normal caller idiom:
eval { Debconf::Plugin::load(...) };
and keeps $@ visible to existing warning/error paths.
Tests added:
- valid plugin/module names are accepted;
- invalid names with path traversal, slashes, dots, spaces, and
metacharacters are rejected;
- malformed Format/DbDriver names do not execute constructed Perl code;
- the existing $@ behavior through caller-side eval is preserved.
Validation performed:
- git apply --check against pristine upstream: OK
- perl -c on modified files: OK
- prove -lr t: 98 tests passing
- trailing whitespace check: clean
Patch attached:
0001-debconf-avoid-string-eval-when-loading-plugin-module.patch
Please let me know if you would prefer a different module name/location for
the helper or a narrower first patch covering only the Format/DbDriver
paths.
Best regards,
Jeremy
El dom, 10 may 2026 a las 14:37, Colin Watson (<cjwatson@debian.org>)
escribió:
Thanks for this. Before I look at the patch in any detail, could you please confirm whether there was any LLM involvement in creating it? It was surprisingly quick given the description of how much you did, and I'd like to check because I do not want debconf's licensing status made ambiguous by the output of an LLM. (Sorry to have to check, but this is the world we apparently live in now.) Regards,
Hi Colin, To clarify more precisely: LLM-assisted local tooling was involved in the bug discovery and analysis workflow, mainly to help navigate the code paths and organize the findings. The patch itself was authored by me using the debconf source tree, your feedback, and the evidence I had already collected while continuing to validate the behavior locally. The turnaround was quick because I had already been investigating and testing the issue in parallel. I understand the provenance/licensing concern, so if this is still not acceptable for debconf, please feel free to disregard the patch as a code contribution. I can instead provide the analysis, tests, and design notes, or prepare a smaller patch following whatever process you prefer. Best regards, Jeremy El dom, 10 may 2026 a las 17:36, Colin Watson (<cjwatson@debian.org>) escribió: