torcontrol: escape backslashes in -torpassword #36374

pull 0xShadowX wants to merge 1 commits into bitcoin:master from 0xShadowX:fix-torpassword-backslash changing 2 files +31 −0
  1. 0xShadowX commented at 5:47 PM on September 28, 2026: none

    With HASHEDPASSWORD authentication, TorController::protocolinfo_cb sends the password as a quoted string, AUTHENTICATE "<password>" (torcontrol.cpp:667). It escapes " but not \.

    Tor parses that argument as a control-spec QuotedString, where a backslash escapes the next character. So:

    • -torpassword=pa\ss reaches Tor as pass, authentication fails and no onion service is created
    • -torpassword=pass\ escapes the closing quote, so the command is malformed

    This escapes backslashes before quotes.

    The new test_password_escaping in feature_torcontrol.py uses the mock control server with HASHEDPASSWORD and -torpassword=pa\ss"word\, and checks the exact AUTHENTICATE line. On master it gets AUTHENTICATE "pa\ss\"word\", with the fix AUTHENTICATE "pa\\ss\"word\\".

    Tested against Tor 0.4.9.12 with HashedControlPassword set for pa\ss"word\: on master bitcoind logs "tor: Authentication failed", with this change authentication succeeds and ADD_ONION creates the onion service.

    AI tools were used to help find this issue and to prepare the patch and test.

  2. DrahtBot commented at 5:47 PM on September 28, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    External sites

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    ACK winterrdog, jpk68

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #36497 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36497.svg"></sub> (test: Add coverage for TorControl SAFECOOKIE authentication by winterrdog)
    • #36142 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36142.svg"></sub> (net: validate Tor onion service replies and cached keys by l0rinc)
    • #35292 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35292.svg"></sub> (test: Add coverage for Tor control HASHEDPASSWORD authentication by winterrdog)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  3. fjahr commented at 7:24 PM on September 28, 2026: contributor

    There is already test coverage suggested for this in #35292, please coordinate with the author there how to proceed.

    I don't have Tor installed here, so this checks the escaping against the control-spec rules rather than a live Tor.

    You should install it and then test it.

  4. 0xShadowX commented at 8:16 PM on September 28, 2026: none

    Installed Tor 0.4.9.12 and tested against it with HashedControlPassword for pa\ss"word\: on master bitcoind gets "tor: Authentication failed", with this change authentication succeeds and ADD_ONION creates the service. I'll ask in #35292 how to combine the test coverage.

  5. in test/functional/feature_torcontrol.py:294 in 898346346b
     289 | +        mock_tor = HashedPasswordTorControlServer(self.next_port())
     290 | +        mock_tor.start()
     291 | +        self.restart_node(0, extra_args=[
     292 | +            f"-torcontrol=127.0.0.1:{mock_tor.port}",
     293 | +            "-listenonion=1",
     294 | +            "-debug=tor",
    


    winterrdog commented at 2:05 PM on October 6, 2026:

    nit: this case only asserts the commands received by the mock, and does not inspect the test node's debug log. -debug=tor only enables debug-level logs (not needed in this case) and can be dropped here


    0xShadowX commented at 8:46 PM on October 6, 2026:

    Dropped it in 9c9bd8cab0f8f5dfebf8d709e0588b42cbdf57fe, thanks. The test still fails on master and passes with the fix.

  6. winterrdog commented at 7:09 PM on October 6, 2026: contributor

    approach ACK


    backslashes are not escaped on present master. to confirm, i ran the test introduced in this PR on master and it failed with:

    <details> <summary>test output log </summary>

    2026-10-03T17:16:33.504732Z TestFramework (ERROR): Unexpected exception:
    Traceback (most recent call last):
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/test/functional/test_framework/test_framework.py", line 145, in main
        self.run_test()
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/build/test/functional/feature_torcontrol.py", line 366, in run_test
        self.test_hashedpassword_auth()
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/build/test/functional/feature_torcontrol.py", line 319, in test_hashedpassword_auth
        assert_equal(mock_tor.received_commands[1], escaped_auth)
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/test/functional/test_framework/util.py", line 94, in assert_equal
        raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
    AssertionError: not(AUTHENTICATE "pa\ss\"word\" == AUTHENTICATE "pa\\ss\"word\\")
    2026-10-03T17:16:33.559119Z TestFramework (INFO): Not stopping nodes as test failed. The dangling processes will be cleaned up later.
    

    </details>


    also, i verified that this PR's motivation is valid and is required by the TorControl spec:

    ... In QuotedStrings, backslashes and quotes must be escaped; other characters need not be escaped.

    from https://spec.torproject.org/control-spec/message-format.html#description-format.


    reply-to: #36374 (comment)

    There is already test coverage suggested for this in #35292, please coordinate with the author there how to proceed.

    yes, we had an exchange and reached consensus here: #35292 (comment)

    since this PR fixes a bug and adds the fix's regression test, while #35292 is test-only, has a larger diff, and covers more test cases, i think it makes sense for this one to go first. it is smaller and should be easier to review, with fewer conflicts with #35292

    neither PR depends on the other, so i can rebase on top of this PR. the remaining conflicts should be straightforward to resolve, and i can handle them afterwards as proposed here: #35292 (comment)

    thanks for bringing this into my view, @fjahr

  7. torcontrol: escape backslashes in -torpassword
    With HASHEDPASSWORD authentication the password is sent as a quoted
    string: AUTHENTICATE "<password>". Quotes in the password are escaped,
    but backslashes aren't. Tor reads a backslash in a quoted string as an
    escape for the next character, so a password like pa\ss reaches Tor as
    "pass" and authentication fails, and a password ending in a backslash
    escapes the closing quote.
    
    Escape backslashes before quotes.
    9c9bd8cab0
  8. 0xShadowX force-pushed on Oct 6, 2026
  9. winterrdog commented at 1:47 PM on October 7, 2026: contributor

    tACK 9c9bd8cab0f8f5dfebf8d709e0588b42cbdf57fe

    successfully built and tested with clang++-19 on FreeBSD 15.0/x86_64 and Linux/x86_64 with clang++-18


    i git-applyied feature_torcontrol.py's patch from this PR onto current master at 9dfde64cc3262329051fd05fffe40eecc786a99f, and the test failed with:

    <details><summary>output</summary>

    ...
    2026-10-07T11:03:15.999507Z TestFramework (INFO): PRNG seed is: 8666784833934009101
    2026-10-07T11:03:16.050000Z TestFramework (INFO): Initializing test directory /tmp/bitcoin_func_test_wwb8jpcz
    2026-10-07T11:03:16.874367Z TestFramework (INFO): Test Tor control basic functionality
    2026-10-07T11:03:18.980178Z TestFramework (INFO): Test that -torpassword is sent as a correctly escaped quoted string
    2026-10-07T11:03:20.142646Z TestFramework (ERROR): Unexpected exception:
    Traceback (most recent call last):
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/test/functional/test_framework/test_framework.py", line 146, in main
        self.run_test()
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/./build/test/functional/feature_torcontrol.py", line 304, in run_test
        self.test_password_escaping()
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/./build/test/functional/feature_torcontrol.py", line 298, in test_password_escaping
        assert_equal(mock_tor.received_commands[1], 'AUTHENTICATE "pa\\\\ss\\"word\\\\"')
      File "/home/madman/Documents/btc/btc-core/my-btc-fork/test/functional/test_framework/util.py", line 94, in assert_equal
        raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
    AssertionError: not(AUTHENTICATE "pa\ss\"word\" == AUTHENTICATE "pa\\ss\"word\\")
    2026-10-07T11:03:20.193788Z TestFramework (INFO): Not stopping nodes as test failed. The dangling processes will be cleaned up later.
    2026-10-07T11:03:20.193916Z TestFramework (WARNING): Not cleaning up dir /tmp/bitcoin_func_test_wwb8jpcz
    2026-10-07T11:03:20.193981Z TestFramework (ERROR): Test failed. Test logging available at /tmp/bitcoin_func_test_wwb8jpcz/test_framework.log
    2026-10-07T11:03:20.194073Z TestFramework (ERROR):
    2026-10-07T11:03:20.194185Z TestFramework (ERROR): Hint: Call /home/madman/Documents/btc/btc-core/my-btc-fork/test/functional/combine_logs.py '/tmp/bitcoin_func_test_wwb8jpcz' to consolidate all logs
    2026-10-07T11:03:20.194235Z TestFramework (ERROR):
    2026-10-07T11:03:20.194285Z TestFramework (ERROR): If this failure happened unexpectedly or intermittently, please file a bug and provide a link or upload of the combined log.
    2026-10-07T11:03:20.194353Z TestFramework (ERROR): https://github.com/bitcoin/bitcoin/issues
    2026-10-07T11:03:20.194400Z TestFramework (ERROR):
    [node 0] Cleaning up leftover process
    

    </details>


    i also tested on TOR running locally with a bitcoind binary built from master with password as pa\ss"word\ and it failed with:

    <details><summary>debug log</summary>

    ...
    2026-10-07T13:27:26Z torcontrol thread start
    2026-10-07T13:27:26Z [tor] Entering Tor control thread
    2026-10-07T13:27:26Z [tor] Attempting to connect to Tor control port 127.0.0.1:9051
    2026-10-07T13:27:26Z [tor] Successfully connected to Tor control port
    2026-10-07T13:27:26Z Bound to 127.0.0.1:8334
    2026-10-07T13:27:26Z Bound to [::]:8333
    2026-10-07T13:27:26Z Bound to 0.0.0.0:8333
    2026-10-07T13:27:26Z [tor] Connected to Tor version 0.5.0.0-alpha-dev
    2026-10-07T13:27:26Z [tor] Supported authentication method: HASHEDPASSWORD
    ...
    ...
    2026-10-07T13:27:26Z [tor] Using HASHEDPASSWORD authentication
    2026-10-07T13:27:26Z [warning] tor: Authentication failed
    ...
    

    </details>


    then, i tested with this PR's patch applied and i got these logs:

    <details><summary>debug log</summary>

    ...
    2026-10-07T13:32:46Z torcontrol thread start
    2026-10-07T13:32:46Z [tor] Entering Tor control thread
    2026-10-07T13:32:46Z [tor] Attempting to connect to Tor control port 127.0.0.1:9051
    2026-10-07T13:32:46Z [tor] Successfully connected to Tor control port
    2026-10-07T13:32:46Z Bound to 127.0.0.1:8334
    2026-10-07T13:32:46Z Bound to [::]:8333
    2026-10-07T13:32:46Z [tor] Connected to Tor version 0.5.0.0-alpha-dev
    2026-10-07T13:32:46Z Bound to 0.0.0.0:8333
    2026-10-07T13:32:46Z [tor] Supported authentication method: HASHEDPASSWORD
    2026-10-07T13:32:46Z [tor] Using HASHEDPASSWORD authentication
    ...
    ...
    2026-10-07T13:32:46Z [tor] Authentication successful
    ...
    

    </details>


    the TOR daemon version details used (built from source -- main at 84caa7e47b1a60c4):

    Tor version 0.5.0.0-alpha-dev (git-84caa7e47b1a60c4).
    Tor is running on Linux with Libevent 2.1.12-stable, OpenSSL 3.0.13, Zlib 1.3, Liblzma 5.4.5, Libzstd 1.5.5 and Glibc 2.39 as libc.
    Tor compiled with GCC version 14.2.0
    

    the command i used to run bitcoind:

    # used linux's default RAMdisk mount (/dev/shm) just to gain a "little" speed.
    # for other systems that do not have it, "/tmp" will do just fine
    ./build/bin/bitcoind \
      -regtest \
      -datadir=/dev/shm/bitcoin-tor-test \
      -torcontrol=127.0.0.1:9051 \
      -torpassword='pa\ss"word\' \
      -listenonion=1 \
      -printtoconsole=1 \
      -debug=tor
    
  10. DrahtBot added the label CI failed on Oct 9, 2026
  11. DrahtBot removed the label CI failed on Oct 9, 2026
  12. jpk68 commented at 4:28 PM on October 21, 2026: contributor

    ACK 9c9bd8cab0f8f5dfebf8d709e0588b42cbdf57fe


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-10-25 15:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me