GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Excess Base64 data ignored after padding by default · Issue #145264 · python/cpython

Excess Base64 data ignored after padding by default #145264

New issue
Copy link
New issue
Copy link
Closed
Closed
Excess Base64 data ignored after padding by default#145264
Copy link
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@serhiy-storchaka
serhiy-storchaka
opened on Feb 26, 2026
Issue body actions

Bug report

After adding the ignorechars parameter for the Base64 decoder (see #144001), decoding in non-strict mode is almost equivalent to decoding with ignorechars including all characters. Except for one detail -- in non-strict mode the first valid padding stops decoding. Any following data is silently ignored. This leads to issues like #137687.

This contradicts RFC 4648, section 3.3 which only allows to ignore the pad character if it is present before the end of the encoded data.

Furthermore, such specifications MAY ignore the pad
character, "=", treating it as non-alphabet data, if it is present
before the end of the encoded data. If more than the allowed number
of pad characters is found at the end of the string (e.g., a base 64
string terminated with "==="), the excess pad characters MAY also be
ignored.

b'YW==Jj' and b'YWJ=j' should be decoded to b'abc', not to b'a' or b'ab'.

So, how are we going to fix this issue? We can simply change the behavior by default -- this may be a breaking change, but it is a bugfix, it breaks incorrect behavior. We can start long process of emitting a FutureWarning, and then changing the behavior few releases later. We can add a new option to alter the behavior and start emitting a FutureWarning by default.

In 3.15+ we can simply pass the ignorechars argument to enable RFC 4648 complaining lenient behavior. The question is about the default behavior.

Linked PRs

  • gh-145264: Do not ignore excess Base64 data after the first padded quad #145267
  • [3.14] gh-145264: Do not ignore excess Base64 data after the first padded quad (GH-145267) #146326
  • [3.13] gh-145264: Do not ignore excess Base64 data after the first padded quad (GH-145267) (GH-146326) #146348
Reacted by Gregory P. Smith and Alexander Shadchin

Activity

Next
  1. serhiy-storchaka
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    3.15bugs and security fixesbugs and security fixes
    on Feb 26, 2026
  2. serhiy-storchaka
    added 2 commits that reference this issue on Feb 26, 2026

    pythongh-145264: Do not ignore excess Base64 data after the first pad…

    50967e0

    pythongh-145264: Do not ignore excess Base64 data after the first pad…

    0229b06
  3. serhiy-storchaka commented on Feb 27, 2026

    @serhiy-storchaka
    serhiy-storchaka
    on Feb 27, 2026
    MemberAuthor
    More actions

    For example, using standard CLI utility base64 on Linux:

    $ echo YW==Jj | base64 -di
    abc
    $ echo -n YWJ=j | base64 -di
    abc

    Using Python:

    $ echo -n YW==Jj | python3 -m base64 -d
    a
    $ echo -n YWJ=j | python3 -m base64 -d
    ab
  4. serhiy-storchaka
    added 2 commits that reference this issue on Mar 22, 2026

    gh-145264: Do not ignore excess Base64 data after the first padded qu…

    4561f64

    [3.14] pythongh-145264: Do not ignore excess Base64 data after the fi…

    a21e7ff
  5. CuriousLearner
    added a commit that references this issue on Mar 23, 2026

    Merge branch 'main' of github.com:python/cpython into fix-pythongh-13…

    3e05fa3
  6. ambv
    added a commit that references this issue on Mar 23, 2026

    [3.14] gh-145264: Do not ignore excess Base64 data after the first pa…

    e31c551
  7. miss-islington
    added a commit that references this issue on Mar 23, 2026

    [3.14] pythongh-145264: Do not ignore excess Base64 data after the fi…

    bd4ab52
  8. ambv
    closed this as completedon Mar 23, 2026
  9. ambv
    added a commit that references this issue on Mar 23, 2026

    [3.13] gh-145264: Do not ignore excess Base64 data after the first pa…

    1f9958f
  10. serhiy-storchaka
    marked "Short circuiting" in base64's b64decode, decode, decodebytes #79013 as a duplicate of this issue on Apr 6, 2026
  11. 11 remaining items

  12. bmwiedemann
    added a commit that references this issue on Apr 19, 2026

    Update python315 to version 3.15.0~a8 / rev 11 via SR 1347984

    ff565b9
  13. jackcurr
    added a commit that references this issue on Apr 21, 2026

    [ie/youtube] Fix PO token sanitization for Python>=3.14.4 (yt-dlp#16453)

    6440292
  14. ljfp
    added a commit that references this issue on Apr 25, 2026

    pythongh-145264: Do not ignore excess Base64 data after the first pad…

    3eba3bd
  15. elboulangero commented on May 7, 2026

    @elboulangero
    elboulangero
    on May 7, 2026
    More actions

    @serhiy-storchaka I tried the base64 example in various containers and can't reproduce your findings.

    debian:latest aka. trixie, which comes with GNU coreutils:

    # dpkg -S bin/base64
    coreutils: /usr/bin/base64
    # dpkg -l | grep coreutils | awk '{print $2 " " $3}'
    coreutils 9.7-3
    
    # echo YW==Jj | base64 -di
    abase64: invalid input
    # echo -n YWJ=j | base64 -di
    abbase64: invalid input
    

    Note the leading a or ab in the output, it means that some characters are decoded before the command fails.

    ubuntu:latest aka. 26.04, which comes with Rust' uutils:

    # dpkg -S bin/base64
    coreutils-from-uutils: /usr/bin/base64
    # dpkg -l | grep uutils | awk '{print $2 " " $3}'
    coreutils-from-uutils 0.0.0~ubuntu25
    # base64 --version
    base64 (uutils coreutils) 0.8.0
    
    # echo YW==Jj | base64 -di
    base64: error: invalid input
    # echo -n YWJ=j | base64 -di
    base64: error: invalid input
    

    And Alpine 3.23.4, which comes with busybox:

    # realpath /bin/base64
    /bin/busybox
    # busybox | head -1
    BusyBox v1.37.0 (2025-12-16 14:19:28 UTC) multi-call binary.
    
    # echo YW==Jj | base64 -di
    abase64: truncated input
    # echo -n YWJ=j | base64 -di
    abbase64: truncated input
    

    What distro did you use for your tests?

    In my tests both coreutils and busybox decoded a and ab which is exactly what Python did. Am I missing something?

  16. serhiy-storchaka commented on May 7, 2026

    @serhiy-storchaka
    serhiy-storchaka
    on May 7, 2026
    MemberAuthor
    More actions

    @shadchin Interesting. It seems that all these examples worked when the length of the encoded data was not the multiple of 3. They worked for tokens which have fixed length.

    @elboulangero It was on Ubuntu 25.10.

    I believe that the base64 implementation in Ubuntu 26.04 does not comply with RFC 4648, because it a) does not error '=' not at the end even without the -i option, b) interprets '=' not at the end as the padding instead of ignoring it.

    $ echo -n QQ==QQ== | base64 -d | hd
    00000000  41 41                                             |AA|
    00000002
    $ echo -n QQQQ | base64 -d | hd
    00000000  41 04 10                                          |A..|
    00000003

    But this is not related to Python implementation.

  17. elboulangero commented on May 8, 2026

    @elboulangero
    elboulangero
    on May 8, 2026
    More actions

    @elboulangero It was on Ubuntu 25.10.

    Trying in Ubuntu 25.10 container then!

    # dpkg -S bin/base64
    coreutils-from-uutils: /usr/bin/base64
    # dpkg -l | grep uutils | awk '{print $2 " " $3}'
    coreutils-from-uutils 0.0.0~ubuntu24
    # base64 --version
    base64 (uutils coreutils) 0.2.2
    
    # echo YW==Jj | base64 -di; echo
    abc
    # echo -n YWJ=j | base64 -di; echo
    abc
    

    So I can confirm your findings now, as you can see! And it also means that Ubuntu 25.10 was an outlier, it was the only one to behave this way.

    Ubuntu 25.10 came with uutils 0.2.2, and Ubuntu 26.04 comes with uutils 0.8.0, so it looks like the behavior changed between those 2 versions.

  18. elboulangero commented on May 8, 2026

    @elboulangero
    elboulangero
    on May 8, 2026
    More actions

    I believe that the base64 implementation in Ubuntu 26.04 does not comply with RFC 464

    FWIW I get the same output on a Debian trixie system (GNU coreutils 9.7-3):

    # echo -n QQ==QQ== | base64 -d | hd
    00000000  41 41                                             |AA|
    00000002
    
    # echo -n QQQQ | base64 -d | hd
    00000000  41 04 10                                          |A..|
    00000003
    

    I suppose uutils has to balance between RFC compliance and bug-for-bug compatibility with GNU coreutils.

    (note: uutils is the Rust re-implementation of GNU coreutils that is now default in Ubuntu)

  19. elboulangero commented on May 8, 2026

    @elboulangero
    elboulangero
    on May 8, 2026
    More actions

    @serhiy-storchaka I have one last question. Should this change be backported to older Python releases? I ask as I'm doing CVE backport for Debian. From the outside, it's not clear why it was backported to 3.13 and no further.

  20. serhiy-storchaka commented on May 8, 2026

    @serhiy-storchaka
    serhiy-storchaka
    on May 8, 2026
    MemberAuthor
    More actions

    The issue looked like potential security issue, but we did not have real examples of possible attacks, so it was not classified as security issue. This change can potentially break the user code (and it turned out that it really breaks the user code), so it was safer to only apply it to maintained versions. If something goes wrong, it will be easier to revert or alter it in maintained versions.

  21. serhiy-storchaka commented on May 9, 2026

    @serhiy-storchaka
    serhiy-storchaka
    on May 9, 2026
    MemberAuthor
    More actions

    I reported the bug in uutils coreutils: uutils/coreutils#12204 .

  22. elboulangero commented on May 11, 2026

    @elboulangero
    elboulangero
    on May 11, 2026
    More actions

    @serhiy-storchaka thanks for clarifying!

  23. DavidRogerio
    added a commit that references this issue on May 27, 2026

    [ie/youtube] Fix PO token sanitization for Python>=3.14.4 (yt-dlp#16453)

    0f0b37a
  24. camachat
    added 2 commits that reference this issue on Jul 22, 2026

    lang/python314: Security update to 3.14.4

    7b1d556

    lang/python314: Security update to 3.14.4

    ec484f0
  25. aalsuwaidi
    added a commit that references this issue on Aug 21, 2026

    Merge upstream master (yt-dlp/yt-dlp) into fork (#1)

    31ab03e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.