[4290] in BarnOwl Developers

home help back first fref pref prev next nref lref last post

Re: BarnOwl 1.10: a zephyr's CC: line is used as a log file name

daemon@ATHENA.MIT.EDU (Alex Dehnert)
Sun Nov 1 23:42:17 2026

Date: Sun, 1 Nov 2026 23:42:07 -0500
To: Jason Gross <jgross@mit.edu>, Daniel Clark <djbclark@gmail.com>
Cc: barnowl-dev@mit.edu
From: Alex Dehnert <alex@dehnerts.com>
In-Reply-To: <CAKObCapg0Lqb6Hw9k6Hdo++p04Z9ewr0KGyTixoPknSb9VbPCA@mail.gmail.com>

It is possible we should uh finally do a 1.11 release, with whatever is 
on master. Does anybody know a reason we shouldn't? (I suppose maybe I 
should try running Barnowl from master, though I don't use barnowl much 
these days so I wouldn't be great at testing it.)

On 11/1/26 01:09, Jason Gross wrote:
> I believe this issue is not present in the Perl-based logging code 
> <https://github.com/barnowl/barnowl/pull/54>, which was merged 6 months 
> after the 1.10 release, 9 years ago. If anyone still uses BarnOwl, I 
> guess it may be worth doing another release. (There has only been one 
> commit in the past seven years.)
> 
> On Sat, Oct 31, 2026 at 9:50 PM Daniel Clark <djbclark@gmail.com 
> <mailto:djbclark@gmail.com>> wrote:
> 
>     Hello BarnOwl developers,
> 
>     I found a security bug in BarnOwl 1.10 logging: a zephyr's CC: line is
>     used as a log file name without the checks that the sender's own name
>     gets. Any zephyr sender can make the receiving client append a message
>     to any file the user can write, or create it. I have also reported it
>     to security@debian.org <mailto:security@debian.org> (2026-11-01). I
>     am sending it to you so that it
>     is fixed upstream and so that you can decide how to tell BarnOwl users.
> 
>     WHAT HAPPENS
> 
>     owl_log_incoming (logging.c) checks the sender's name before using it as
>     a file name under logpath: 1 to 35 printable ASCII characters, first
>     character alphanumeric, no '/', not "." or "..". For a personal zephyr
>     it then also logs the message to every name on its CC list
>     (owl_message_get_cc_without_recipient: the first body line, if it starts
>     with "CC:"). Those names come from the sender and get none of those
>     checks: g_build_filename(logpath, short_zuser(name), NULL), then
>     fopen(..., "a") on the logger thread. owl_log_outgoing has the same
>     loop, for the user's own CC lines.
> 
>     IMPACT
> 
>     A personal zephyr whose body starts with the line "CC:
>     ../../.ssh/authorized_keys", followed by a line holding an SSH public
>     key, makes the receiving client append the whole logged entry (header
>     lines, then the body) to ~/.ssh/authorized_keys. sshd ignores the header
>     lines and accepts the key line. Appending to ~/.bashrc or creating
>     ~/.ssh/rc gives code execution the same way. It needs personal logging
>     on ("set logging on", loggingdirection "in" or "both", the documented
>     setup), no authentication and no action by the user.
> 
>     AFFECTED
> 
>     BarnOwl 1.10 (tag barnowl-1.10), tested as Debian barnowl 1.10-2+b9 on
>     Debian 13. I did not check other versions; the code looks old, so
>     earlier ones are probably affected too.
> 
>     REPRODUCTION (scratch directory; nothing outside it is touched)
> 
>     Use a scratch HOME with the config dir /tmp/T/home/.owl and logpath
>     /tmp/T/zlog/people. Put this in /tmp/T/home/.owl/startup:
> 
>          set logging on
>          set loggingdirection both
>          set logpath /tmp/T/zlog/people
>          perl BarnOwl::queue_message(BarnOwl::Message->new(
>            type=>'zephyr', direction=>'in', class=>'message',
>            instance=>'personal', sender=>'eve@ATHENA.MIT.EDU
>     <mailto:eve@ATHENA.MIT.EDU>',
>            recipient=>'user@ATHENA.MIT.EDU
>     <mailto:user@ATHENA.MIT.EDU>', private=>1,
>            isprivate=>'true', realm=>'ATHENA.MIT.EDU <http://
>     ATHENA.MIT.EDU>', opcode=>'',
>            auth=>'NO', host=>'h', hostname=>'h', zsig=>'z',
>            body=>"CC: ../../victim\nssh-ed25519 AAAAFAKEKEY attacker\n",
>            time=>scalar(localtime), unix_time=>time()))
>          perl our $t = BarnOwl::Timer->new({after=>4,
>            cb=>sub{BarnOwl::command("quit")}})
> 
>     Then run: HOME=/tmp/T/home script -qfc 'barnowl -n -s /tmp/T/home/.owl'
>     /dev/null. With 1.10-2+b9, /tmp/T/victim exists (outside logpath) and
>     holds the logged entry. With the patch below it is not created, and a CC
>     to an ordinary user name is still logged. A real zephyr goes through the
>     same function.
> 
>     TEMPORARY WORKAROUND FOR USERS
> 
>     Until a fixed BarnOwl is installed, users can stop the bug by turning
>     personal-zephyr logging off:
> 
>        - Put "set logging off" in ~/.owl/startup (replacing "set logging
>     on")
>          and run ":set logging off" in a running client. Personal
>     zephyrs are
>          then not logged, in either direction. Class logging ("set
>          classlogging on") is unaffected, because class names get the
>     sender-
>          name checks and have no CC handling.
>        - "set loggingdirection out" should also stop incoming personals from
>          being logged while keeping a log of what you send. I have not
>     tested
>          that variant; the "logging off" one is based on reading the
>     code and
>          on how the logging variables gate the logger, and I did not run it
>          against the exploit.
>        - Weaker, partial measures: make ~/.ssh/authorized_keys,
>     ~/.bashrc and
>          ~/.profile read-only (chmod 400, or chattr +i as root). This does
>          not help against files that do not exist yet, such as ~/.ssh/rc or
>          ~/.bash_login, and any file the user can write stays reachable.
>        - Run the client in a sandbox (bwrap, firejail, a separate
>          unprivileged account) that can write only ~/.owl and the log
>          directory. I have not tried this.
> 
>     FIX
> 
>     Apply the sender-name rules to every CC name, in both loops. This patch
>     against 1.10 does that (it also works as a Debian quilt patch,
>     debian/patches/0001-log-validate-cc-names.patch). I tested the name
>     function on its own, and the behaviour above with a Debian 1.10-2 build
>     plus this patch. I did not review the jabber and aim branches of the
>     logger, which also build file names from message data.
> 
>     --- a/logging.c
>     +++ b/logging.c
>     @@ -205,6 +205,26 @@
>         g_free(buffer);
>       }
> 
>     +/* A name taken from a message is used as a file name under the log
>     directory only if
>     + * it could be a user name: 1-35 printable ASCII characters, the
>     first alphanumeric,
>     + * no '/', and not "." or "..". The CC: line of a zephyr is written
>     by its sender, so
>     + * without this a CC of "../../.ssh/authorized_keys" makes us append
>     the message to
>     + * that file (CVE pending). */
>     +static int owl_log_name_is_safe(const char *name)
>     +{
>     +  size_t i, len;
>     +
>     +  if (!name) return 0;
>     +  len = strlen(name);
>     +  if (len < 1 || len > 35) return 0;
>     +  if (!g_ascii_isalnum(name[0])) return 0;
>     +  for (i = 0; i < len; i++) {
>     +    if (name[i] < '!' || name[i] >= '~' || name[i] == '/') return 0;
>     +  }
>     +  if (!strcmp(name, ".") || !strcmp(name, "..")) return 0;
>     +  return 1;
>     +}
>     +
>       void owl_log_outgoing(const owl_message *m)
>       {
>         char *filename, *logpath;
>     @@ -220,10 +240,12 @@
>           cc = owl_message_get_cc_without_recipient(m);
>           while (cc != NULL) {
>             temp = short_zuser(cc->data);
>     -      filename = g_build_filename(logpath, temp, NULL);
>     -      owl_log_append(m, filename);
>     +      if (owl_log_name_is_safe(temp)) {
>     +        filename = g_build_filename(logpath, temp, NULL);
>     +        owl_log_append(m, filename);
>     +        g_free(filename);
>     +      }
> 
>     -      g_free(filename);
>             g_free(temp);
>             g_free(cc->data);
>             cc = g_list_delete_link(cc, cc);
>     @@ -410,7 +432,7 @@
>           cc = owl_message_get_cc_without_recipient(m);
>           while (cc != NULL) {
>             temp = short_zuser(cc->data);
>     -      if (strcasecmp(temp, frombuff) != 0) {
>     +      if (strcasecmp(temp, frombuff) != 0 &&
>     owl_log_name_is_safe(temp)) {
>              filename = g_build_filename(logpath, temp, NULL);
>               owl_log_append(m, filename);
>              g_free(filename);
> 
>     I can send a pull request if you prefer that, or answer questions. A CVE
>     has not been requested; Debian security may assign one, and you may want
>     to coordinate with them on the timing of any announcement. If you need
>     more detail, reply to me directly.
> 
>     Daniel J. B. Clark
>     djbclark@gmail.com <mailto:djbclark@gmail.com>
>     djbclark@mit.edu <mailto:djbclark@mit.edu>
> 

home help back first fref pref prev next nref lref last post