There are 3 open security issues in forky.
There are 3 open security issues in bullseye.
commit e034fde6ec8f7fd0b3f6fb7b0f9abfdfdd7a227c
Author: Colin Watson <cjwatson@debian.org>
Date: Sun May 24 13:08:29 2026 +0100
releasing package putty version 0.84-1
commit d8ff1af19078941b6f0a17aa480b60115da7372a
Merge: e9eb124 568b97d
Author: Colin Watson <cjwatson@debian.org>
Date: Sun May 24 12:54:49 2026 +0100
New upstream release (0.84)
commit 568b97db2c1350567b4b7d9477e163e45f05c36c
Merge: d8381c2 cda57ec
Author: Colin Watson <cjwatson@debian.org>
Date: Sun May 24 12:54:49 2026 +0100
Import putty_0.84.orig.tar.gz
commit cda57ec785f52a9092f529b206059355646caab6
Author: Simon Tatham <anakin@pobox.com>
Date: Thu May 14 20:21:24 2026 +0100
Update version number for 0.84 release.
commit ba3ed53e0bf6682f89940bc2c3e83da6b1524024
Author: Simon Tatham <anakin@pobox.com>
Date: Thu May 14 18:15:56 2026 +0100
Don't call sfree after ssh_rsakex_freekey.
ssh_rsakex_freekey(), given an RSAKey structure, calls freersakey() to
free all the pieces dangling off it, and then finally frees the RSAKey
itself. So calling ssh_rsakex_freekey() and _then_ sfree() is a double
free.
commit e5242181c1a2d8bf58bedfd9b61251ca6af2ca63
Author: Simon Tatham <anakin@pobox.com>
Date: Sun May 10 14:02:55 2026 +0100
Windows on Arm: use hardware SHA-512 accel if available.
I have a new WoA test machine which has the necessary CPU extension,
and also, the docs for IsProcessorFeaturePresent have been updated to
include an id you can use to test for it. So now Arm Windows PuTTY can
detect support for hardware-accelerated SHA-512, and turn it on if
available.
commit 29d8bd9b1bf47c81a45acb401e0a821644fcc036
Author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
Date: Sun May 3 17:04:24 2026 +0100
Docs: index 'wake-on-LAN', on general principles.
(cherry picked from commit df256593e9716a191e9752d926064b32b5cee5a2)
commit adc9c135eed96ad0641e5783a2bed71dfc4c25db
Author: Simon Tatham <anakin@pobox.com>
Date: Sun May 3 08:48:49 2026 +0100
Docs: add wake-on-LAN as a use case for pre-connect commands.
Ian suggested this to me the other day, and it seems worth adding to
the docs. In fact it might actually be a _better_ use case than port
knocking, so I've listed it first, relegating port knocking to second
place.
(Since a wake-up script would need to wait until the target server is
sufficiently booted up to be listening for SSH, this use case benefits
particularly from my rework to run the hook command asynchronously.)
(cherry picked from commit b7b8389999878d19a6685ada944219d7d82a2c38)
commit 65b8f37c34cd80680693e813e0081cdafaf58324
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Mar 28 19:25:24 2026 +0000
Remove bogus assertion in ecc_weierstrass_add.
The comment next to the assertion says that it's checking for either
identical inputs or mutually inverse ones: that is, input curve points
with the same affine x-coordinate. But in that case we should have
checked lambda_n, the _numerator_ of the slope of the line through the
input points. Instead we were accidentally checking lambda_d, the
denominator.
ecc_weierstrass_add_general gets this right: it checks lambda_n to
decide whether to use the output of the unequal-point addition formula
or the doubling formula.
The obvious fix is to replace the assertion with one checking
lambda_n. But that doesn't work, because it's possible during
legitimate operation to cause a call to ecc_weierstrass_add that would
fail the fixed version of the assertion! Because of constant-time
considerations, every time ecc_weierstrass_multiply consumes a bit of
the exponent, it calculates both of two possible outputs of that
iteration step, and then selects between them. And sometimes one of
those outputs _does_ involve passing mutually inverse values to
ecc_weierstrass_add. That's harmless if the result of that calculation
is thrown away by the caller – except that it's not harmless if you
fail an assertion and crash before getting back _to_ the caller!
(With the current style of exponentiation loop, the case that would
fail the 'right' assertion involves raising a point P to its own order
minus 1, because we're consuming the exponent from the MSB downwards,
so at every stage we choose between P^(2k) and P^(2k+1). But switching
to the LSB-upwards style of repeatedly squaring to make P^{2^n} and
conditionally multiplying in each of those, you'd still have the same
failure, just in a different place – the failing case would involve
raising P to the power of its own order with the leading 1 bit
removed.)
So that's why we can't replace the bogus assertion with a better one.
Instead, the only thing to do is remove the assertion completely, and
rely on callers to have already checked that exponents are in
range (hence the precautionary fix in ecdsa_public in the previous
commit).
What about triggering the _actual_ wrong assertion? Guido Vranken
reported this issue and included a test case that demonstrates that
it's possible to trigger the bug deliberately. His example case is a
P256 curve point P such that 10P and 11P have the same y-coordinate,
and therefore trying to compute 21P will add those values together and
fail the previous assertion. Worse, it's easy to construct a malicious
P256 public key and signature such that attempting to verify that
signature provokes the same crash – no matter what the message is. So
this is a DoS vector for an on-path attacker, who can make PuTTY crash
by substituting this fixed P256 key and signature in the cleartext
initial key exchange of any SSH connection.
(Only a DoS, though: PuTTY is always compiled with assertions enabled,
so it won't do anything _worse_ than crash with an unhelpful message.)
commit 7db1f655bbdd30040f983e71b36ea369a226faea
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Apr 1 08:49:53 2026 +0100
ecdsa_public: reduce exponent mod the right thing!
During (NIST-style) ECDSA key generation, we generate a random
exponent, and raise the base point to that power. So the exponent
ought to be reduced mod the order of the base point. But in fact we
were reducing it mod the prime order of the curve's field – the same
error as I just fixed in the test suite in the previous commit.
Luckily, this mistake is benign. That reduction is only precautionary
in any case, and in fact never comes up, because keygen/ecdsa.c has
already generated its random exponent using the _correct_ bounds. And
G_order is always smaller than p, so the bogus reduction mod p never
did anything.
commit cd18fb76f9d8b500b4e25e5553347b7a59eb3569
Author: Simon Tatham <anakin@pobox.com>
Date: Mon Mar 30 20:27:29 2026 +0100
Tidy up the elliptic curve multiplication tests.
When you test raising a group element to a power, the power only
matters mod the order of the original element. So we should be
reducing our test powers mod that, rather than mod the prime used in
the curve's field. Now in all three test functions we reduce mod
curve.G_order.
This also involved making the curve.G_order field exist at all in the
Python reference implementation of the Montgomery curves. I'd left it
out. But that's easy, because those curves correspond closely to the
two Edwards ones and share their values of G_order.
Also, testMontgomeryMultiply wasn't even reducing mod the _right_
256-bit prime: it was using p256.p rather than curve25519.p,
presumably from a copy-paste error (p256.p is used in the Weierstrass
function right next to it). Now all three functions assign the test
curve to a variable of the same name, so that they _deliberately_ look
alike.
commit 3c598400e495645fec921781a1065303039a7d17
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Apr 15 17:16:00 2026 +0100
Fix handling of ECONNREFUSED in GTK 1 builds (!)
While testing the GTK 1 version of the code I touched in the previous
commit, I tried to connect to an SSH server which has both IPv6 and v4
addresses but is refusing connections to port 22 on the v6 address.
GTK2 and GTK3 PuTTY cheerfully fall back to v4; GTK1 PuTTY bombed out
immediately with a 'Connection refused' message box.
Turned out this was because I had performed an asynchronous connect(2)
operation; called uxsel_set() to ask for only writability
notifications on the socket (that being how you find out that your
async connect attempt has finished); uxsel_set() dutifully called
gdk_input_add() with only the GDK_INPUT_WRITE flag; and GTK1 called me
back with GDK_INPUT_READ as well as GDK_INPUT_WRITE set! So network.c
tried to process the readability notification first, leading to the
wrong branch of the network error handling code.
Easily fixed by remembering what I/O flags we actually _asked_ for,
and ignoring any others that GTK chooses to set in the callback.
commit ea1038a25b54dbddc29ba46d27d330ce633a0b7b
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Apr 15 16:23:02 2026 +0100
GTK: switch embedded icons to raw RGBA rather than xpm.
A test-build on current Debian sid revealed that in the latest version
of GdkPixbuf, gdk_pixbuf_new_from_xpm_data() is marked as deprecated,
causing build failures at -Werror.
It turns out that ever since the start of GTK 2, GdkPixbuf has had a
reasonably nice API call gdk_pixbuf_new_from_data() which takes a
buffer of raw 32-bit RGBA pixels plus width/height/stride parameters,
and moreover, uses the data in place rather than copying it – it takes
ownership, but you provide a function to free it. Or if it's in the
static data segment, you just don't _even_ provide a free function.
Not only that, but it turns out the XPM parsing was done by a spare
shared library that's not embedded in the GdkPixbuf main code, and a
warning in the current docs say that that library can't be 100% relied
on to be present everywhere!
So using raw RGBA data seems better all round in any case, and since it
isn't newly introduced, I don't need to make it conditional on a very
new version of anything. We can just use that function for all GTK 2.x
and 3.x builds, and use the XPM approach only on GTK 1.
commit 85703a848b7ae8d931c4371c16d6861f8f1087bd
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Apr 15 09:44:10 2026 +0100
Add a horizontal scrollbar in the Windows Event Log.
Now you can see the end of a long message without having to paste it
into another application.
As mentioned in the comment, this doesn't seem to be setting exactly
the right scrollbar extent, but I don't know why not. Still, it's
overestimating rather than underestimating, which is the better kind
of error (you can still read all the text!), so this is better than
nothing.
commit 7a7da3365a6d7b74382f96fde42509d7ae81cf1d
Author: Simon Tatham <anakin@pobox.com>
Date: Tue Apr 14 10:34:09 2026 +0100
Switch unix/pty.c to use the new SubprocessWaiter.
The mechanisms in there - SIGCHLD handler, self-pipe with uxsel, wait
loop, tree of known subprocesses indexed by pid - are all replicated
in the new centralised system, so there's no need to have two copies
of them.
This also extends the Unix-specific API of SubprocessWaiter to add a
couple of extra 'forcibly do a thing you would have got round to
later' functions.
commit ff89d584c55f281aca40609d65f18e25c9ef20fa
Author: Simon Tatham <anakin@pobox.com>
Date: Tue Apr 14 10:29:53 2026 +0100
Refactor pty_real_select_result. (NFC)
pty_real_select_result was a monolithic function which included
handling the result of waitpid() (indicated by passing magic -1 values
as fd and event), or actually reading data from the pty (in the
absence of those special values), and cleanup functionality if either
of those things indicated that it was time to finish the session.
Now the magic values are gone: waitpid() results are handled in their
own function. Also the shared cleanup functionality lives in the new
pty_finished() routine, called from both that and the remainder of
pty_real_select_result(), which now just handles _actual_ results of
select() reporting activity on the pty fd.
This patch is completely boring: it just moves existing code around
and reindents it. The interesting change will come in the next commit;
this one just separates the boring parts of the work, to make the
interesting patch easier to read.
commit a0659c2a614b64a05952701fdd96a7bf992efe4d
Author: Simon Tatham <anakin@pobox.com>
Date: Mon Apr 13 14:02:44 2026 +0100
Run pre-connect commands via platform_start_subprocess.
This fixes the limitation of the previous execute_command_hook() that
it blocked the whole PuTTY process while waiting for the pre-connect
command to terminate. Now, if the subcommand unexpectedly takes a long
time, PuTTY itself will still be responsive – you can check its Event
Log to see what's going on, or close it if you realise the command is
never going to succeed, or simply copy-paste stuff from the terminal
window while you wait.
platform_start_subprocess opens three pipes to run the command in (on
both Unix and Windows), for stdin, stdout and stderr. Here, stdin is a
liability: we don't have any input to give the command, so if it were
to stop to try to read from stdin, it would blockk. Therefore we send
an outgoing EOF immediately by closoing the pipe to the command's
stdin, so that instead of blocking, it will immediately find out
there's no input for it.
commit 6aab75a4ec760b3d8a2fa94260a4ebb6ca815b74
Author: Simon Tatham <anakin@pobox.com>
Date: Tue Apr 14 16:19:41 2026 +0100
HandleSocket: stop tying input and output EOF together.
If a HandleSocket is used with a pair of pipes, we can send outgoing
EOF by closing the output pipe, without necessarily closing the input
pipe. But we were unconditionally closing both anyway.
This makes no difference to usages involving named pipes; it only
makes a difference with local proxy subprocesses.
commit 1bf88ffbe8ddd85f60e601c59a77950e23ac7e74
Author: Simon Tatham <anakin@pobox.com>
Date: Tue Apr 14 09:50:43 2026 +0100
New centralised system for waiting for subprocesses.
There's a new 'SubprocessWaiter' object, which you can optionally ask
for as an extra result of platform_start_subprocess, and then tell it
how to give you a callback when the subprocess terminates.
Not yet used: the existing use of platform_start_subprocess only cared
about the output pipe of the subprocess anyway, so it passes NULL as
the extra output pointer, indicating that it doesn't need a waiter.
commit ccd3d3715f3d6ec8eb89b9fbd20f743a00551269
Author: Simon Tatham <anakin@pobox.com>
Date: Mon Apr 13 13:02:47 2026 +0100
Centralise the call to execute_command_hook.
Now there's a function new_main_connection() in proxy/newmain.c, which
is called in place of new_connection() when the connection you're
making is the primary one of the session (as opposed to some sub-thing
like a port forwarding). So now running the pre-connect command is
done inside there.
This is more DRY in general, but more specifically, allows
new_main_connection() to be implemented in a more sophisticated way.
The new function differs in API from new_connection() in that it
requires a LogContext as well as all the other parameters.
commit af996b5ec27ab79bae3882071b9d6acf16044549
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Feb 25 08:29:58 2026 +0000
eddsa_verify: add check for out-of-range s.
The integer s in an EdDSA signature is treated as an exponent: the
curve's base point is raised to that power. (OK, multiplied by it, if
you use the elliptic curve notational convention rather than the
general group convention.) Therefore, in principle, it doesn't make
any difference if s varies by a multiple of the base point's
order (which is around 2^252, therefore a larger s still fits easily
within the 256-bit space for it in the signature encoding). However,
RFC 8032 requires s to be strictly less than that order, so that
there's a single canonical encoding for any given signature.
I'm not treating this as a vulnerability because I don't believe
there's any situation in SSH where canonicality of signatures is
important. But it should be fixed, nonetheless.
In the fix, it's OK to use an ordinary if statement to check the bound
on s, because they're visible to everybody anyway: the integer s is
encoded directly in the signature, and the bound we're checking it
against is a well-known public integer, so nothing new is revealed by
any timing side channel proving that that was the reason for the
rejection. (Not even if the message being signed were secret, which it
is in SSH: the validation of s doesn't depend on the message.)
Thanks to Yujie Zhu for the report.
commit af33ecdc88fed05bfcd08a6d6d60c35775c743bd
Author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
Date: Wed Feb 18 23:39:27 2026 +0000
Docs: improve pre-connect command documentation.
Document %host and %port escapes.
Document -preconnectcommand command-line option.
Index 'port knocking'.
commit 458652ddc8a405bf86635abbc618dc5c8e7a11bf
Author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
Date: Wed Feb 18 23:49:42 2026 +0000
Add -preconnectcommand to usage messages.
commit 1c0490dd3cc3c8432f42c46af10091a4f51e395c
Author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
Date: Wed Feb 18 23:38:43 2026 +0000
Add an accelerator for pre-connect command.
commit 37c7e6975d08a027f090f1184a1196c9ddabf098
Author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
Date: Wed Feb 18 23:38:25 2026 +0000
Disallow -preconnectcommand in pterm.
commit 503d6139d5e1a7c727343e7c06c39778f18dfb25
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Jan 10 09:25:18 2026 +0000
New feature: a pre-connection command hook.
Patch due to Jonathan Senkerik. This adds a new config feature to spawn
a subprocess, on both of Windows and Unix, just before making the main
outgoing network connection of the session. The idea is that you'd use
it to run a tool that temporarily opens the network port you plan to
connect to, such as a port knocker or similar.
The subprocess is run synchronously: PuTTY waits for it to terminate
before continuing with the session. Its output and exit status are
logged in the Event Log, although if it fails, PuTTY will proceed with
the connection attempt anyway. (You could imagine that a port knocker
might leave the port open for long enough that a second connection
shortly afterwards might succeed even if the knock command failed for
some reason.)
commit f4a99c58a162094501219232a1d1b53edc75d48a
Author: Simon Tatham <anakin@pobox.com>
Date: Sun Feb 8 15:22:17 2026 +0000
Move Telnet proxy command formatting into utils.
The 'utils' version of the function takes the format string as a
parameter rather than extracting it from CONF_proxy_telnet_command, so
that it can be reused to format things not kept in that slot.
commit 5b6e89cb66d9c8f74bcc741b304cc5206699d4f6
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jan 30 12:30:51 2026 +0000
Don't accidentally interpret DCS escapes as OSC.
Every piece of code that sets term->termstate to SEEN_OSC also sets
term->osc_type to identify which kind of generally OSC-shaped escape
sequence is being processed, such as DCS or APC or OSC proper. But the
latter setting was having no effect, because immediately on arriving
in the SEEN_OSC case handler, we would unconditionally reset
term->osc_type back to OSCLIKE_OSC, treating them all as OSC anyway!
Reported by a user, who was finding that vim was sending the DSC
sequence ESC P z z ESC \ on startup, and this was resetting the window
title to "z". PuTTY's _intended_ handling of DSC sequences is to
consume them without messing up the display, and otherwise ignore
them. It had failed to ignore this one!
Added a small test of window-title setting to test_terminal.c, mostly
so that it can contain a regression test for that bug.
commit 4448d1a81e934b8f697d8e7bcc66219e38924259
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jan 23 23:32:06 2026 +0000
Unix: create ~/.putty/sshhostcas if necessary.
Jacob points out that Unix PuTTY contained no code to create this
directory, in which records are stored for each CA you trust to sign
host keys. That's embarassing! I must have created the directory
manually during initial development, probably because I wrote and
tested the code that loads and uses its contents before the GUI
configurer. And then I never re-tested from a clean config directory,
which would have made me realise that saving didn't work if the
containing directory didn't already exist.
(I know at least a few people have been _using_ PuTTY's certificate
support since it was added – but apparently not many on Unix!)
commit c15d4d7b1acf99ae21c67f5c7c65884b9959149d
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Jan 14 12:47:23 2026 +0000
Fix edge case in ecc_weierstrass_add_general doubling.
ecc_weierstrass_add_general() is the function that you call to compute
P+Q if you don't know whether or not P=Q (in which case different
calculations are required). It calculates the answers for both the P≠Q
and P=Q cases, and selects between them (in constant time, so as not
to give away whether P=Q).
But we use Jacobian coordinates (two numerators and a denominator) to
represent Weierstrass curve points, so a point has multiple
representations, using different choices of denominator. In the case
where P and Q were different representations of the same point, using
different denominators, ecc_weierstrass_add_general() was doing the
wrong thing, and returning something that wasn't even a valid elliptic
curve point.
The root cause was that we start by transforming both inputs to be
over a common denominator for the P≠Q case, and we should have done
the P=Q calculations relative to _that_ denominator, which is the one
expected by the shared epilogue code. But instead we used the
denominator of one of the input points. And if P,Q have identical
_representations_, then this makes no difference, so the existing
tests of adding a point to itself didn't spot the problem.
This is a bug in our ECC arithmetic, but happily, not a vulnerability,
because exploiting it requires work equivalent to recovering the
private key.
ecc_weierstrass_add_general() is used when validating an ECDSA
signature: you use it to calculate (hw)G + (rw)P, where G is the group
generator, P is the public key, h is derived from a hash of the
message, and r,w come from the signature. So to trigger the bug you
need the two addends to be the same, i.e. (hw)G = (rw)P. Cancelling w,
you need hG = rP.
But if an attacker trying to forge a signature was able to find any
pair (h,r) at all such that hG = rP, then inverting r mod the group
order and multiplying both sides by its inverse r⁻¹, you would have
(r⁻¹h)G = (r⁻¹r)P = P. And that would mean r⁻¹h was precisely the
private key.
So if an attacker could do that at all, then they wouldn't _need_ to
exploit any buggy behaviour in ecc_weierstrass_add_general(). They'd
have the private key by that point, so they could use it to construct
a signature that _didn't_ trigger this bug, and that PuTTY would
accept with or without the bug fix.
Thanks to Guido Vranken for the report.
commit fd08a7754bbc94ec7fb841c4858897d8ea9f448c
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Jan 10 09:15:09 2026 +0000
Weed the FAQ.
It's finally time to clear up some of the hilariously outdated
questions, like things about PocketPC, or warnings about behaviour
changes in some prehistoric version like 0.5x, or warnings about
things that went wrong in Windows XP SP2.
Apart from straight-up deletions, I've also updated the questions
about what ports exist, including updating the status of the
non-Mac-port to explain that it's not only unfinished but now also
bit-rotted. And I've replaced the "why is there even a Unix PuTTY when
OpenSSH exists?" with a more general "why use PuTTY when OpenSSH
exists?", now that OpenSSH exists for Windows too.
The terminal-types question now acknowledges that a 'putty' terminal
type exists; the copy-paste question now starts 'by default' and
explains that these days you can reconfigure if you prefer more
Windows-like behaviour.
The _two_ FAQ entries about "Out of memory" are gone, as is the text
about it in errors.but. Nowadays PuTTY won't just pass an arbitrary
32-bit packet size field to malloc at all: both SSH and SFTP will cap
at some idea of the maximum sensible size, and if they see a larger
value than that, report some other more specific error message.
It's possible that some new material might be useful. For example,
I've deleted both questions about SSH-2 and SSH-1 support, but there
_is_ still something to say about SSH-1 support (namely, the fact that
PuTTY still provides it for talking to legacy devices with firmware
SSH-1 servers). But I'm working on the principle that if in doubt I
interpret "FAQ" in the literal sense: once we find out what questions
people actually do ask frequently, we can put those questions back in.
And, with some nostalgic regret, I've included Crazy Aaron's Putty
World among the garbage-collected questions. He managed to get a link
from us by sending us free samples which caught us in a whimsical mood
back when PuTTY wasn't as famous as it now is, and I'm sure it proved
to be a good investment for him. But even if that business is still
around, it's not true any more that people run across the PuTTY web
site and mistake it for actual putty.
commit c494fe86d63fb2f2b2f842513e0b07c63f075186
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Jan 10 08:55:28 2026 +0000
Clarify the LLMs FAQ entry.
I just re-read it and realised that "No AI or LLM code is included in
PuTTY" can be read two ways. I meant it to be about code that
_implements_ an LLM, because that was what the person asking me this
question was concerned about. But the way I worded it, it could also
be misread as a promise that none of PuTTY's code was _generated by_
an LLM. That wasn't what I meant, so I've clarified the language so
that it's clearer that it means the former.
I'd _like_ to be able to give the latter promise too! Certainly I have
never used an LLM to generate code to go into PuTTY (or into anything
else I've written). But I can't make the same promise on behalf of all
our contributors, because I'd have no way to know.
commit 8cdd0bbfe3662f6e747b15a2127070578631aa70
Author: Simon Tatham <anakin@pobox.com>
Date: Sun Jan 4 19:03:58 2026 +0000
Add 64-pixel images to the Windows .ico files.
Requested by a user. I guess as screen resolutions go up, larger icons
become useful.
commit d222b73b675489e5c448bf4513ec84d33cf8a64e
Author: Simon Tatham <anakin@pobox.com>
Date: Sun Jan 4 19:01:14 2026 +0000
Refactor icons/Makefile.
Instead of typing out all the PNGs longhand that go into each .ico
file, we now generate the list of file suffixes once using GNU make
text processing, and then make each rule's dependencies by
transforming that list. Makes it easier to add a new icon size.
commit 995b63a82bac4f6985958cb92943e807a9f35736
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jan 2 12:54:11 2026 +0000
It's a new year.
According to source control, this is the first time *I've* remembered
to update the copyright date since 2005! Every year since then, it's
been Jacob, except for 2013, when apparently nobody remembered at all.
commit 3fd66c6796bfcf9e9e515c915de9cf8ec9bed6a9
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jan 2 12:25:53 2026 +0000
OpenSSH key import: support aes256-gcm encrypted keys.
A user reports that 1Password will choose this cipher to encrypt the
'new' non-PEM OpenSSH key file format. You can make OpenSSH itself do
the same, using the option "-Z aes256-gcm@openssh.com" during key
generation.
I don't know _why_ 1Password chooses this, because in this context,
the MAC built in to AES-GCM isn't used - the OpenSSH key file format
has no MAC at all. So AES-GCM becomes just an alternative form of
counter-mode encryption, with a more restricted shape of IV. This also
requires a manual workaround to avoid the keystream being out of sync,
because the MAC isn't there to consume the first block of it.
commit 78599038a3f78e7521c68c019993a0c34504ce37
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jan 2 12:24:54 2026 +0000
cryptsuite: remove a stray import statement.
What was that doing _there_, deep in the middle of a function? I have
to assume I hacked it in temporarily to go with a diagnostic print,
and then took out the more obvious print statement leaving the
spuriopus import behind.
commit 36a049664915bd9e4493bc38c585f8d27c2ec7a2
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jan 2 10:22:15 2026 +0000
Remove spurious \n in OpenSSH key import diagnostics.
The output "errmsg" inconsistently had a newline in some cases and not
in others. In fact it doesn't need one, so I've removed the unwanted
ones.
commit e9eb124d22b856320504b77fb80f04f521a37f34
Author: Colin Watson <cjwatson@debian.org>
Date: Sun Nov 23 11:54:08 2025 +0000
Drop "Rules-Requires-Root: no", default as of dpkg-dev 1.22.13
commit 148c3b01338592d606e5756b5f22524c70b4246c
Author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
Date: Thu Nov 6 14:19:43 2025 +0000
FAQ: add link from faq-hostkeys to '-hostkey' docs.
commit f9cbe226ebc0bb0269328a7b2a471e821204391f
Author: Simon Tatham <anakin@pobox.com>
Date: Thu Oct 23 12:23:37 2025 +0100
Fix pointer-handling bug in write_random_seed().
Thanks to Joshua Rogers for the report: if writing the random seed
took more than one call to write(2), then we'd add the wrong value to
the data pointer between calls. Happily this is very unlikely to have
actually happened, because random seed files are tiny and surely
write() will in practice manage to write it all first time. But still
needs fixing.
commit c4fe7b0a7a88933c4856dafe4b811deaa2dbef89
Author: Simon Tatham <anakin@pobox.com>
Date: Sun Oct 19 11:18:12 2025 +0100
Add a FAQ about LLM usage, or rather, the lack thereof.
It was asked this week, and I fear it won't be the last time.
commit 9cb330cf4d7b2f3aa7c5fdcbb3ca64dad3dded44
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Sep 27 09:25:26 2025 +0100
udp.but: fix braino in example function names.
Two of the wrapper functions in my example 'trait' had names
appropriate to the implementation functions for a particular concrete
type. Probably copy-paste with inadequate editing while I was writing
it.
commit 0396d3a279e1338c07334471aa72d0be25b758fd
Merge: eccb46f e16bcf8
Author: Colin Watson <cjwatson@debian.org>
Date: Sat Sep 20 23:06:23 2025 +0000
Merge branch 'dh-restore' into 'master'
d/rules: Use `dh_assistant restore-file-on-clean`
See merge request ssh-team/putty!7
commit e16bcf8b98dd752c342eedfcdd55c74b949afbf6
Author: Niels Thykier <niels@thykier.net>
Date: Sat Sep 20 06:40:45 2025 +0000
d/rules: Use `dh_assistant restore-file-on-clean`
This replaces a handrolled restore with `debhelper`'s built-in one
(accessible via `dh_assistant` since `debhelper/13.12`).
commit e952f37f02d7a25e85a3cb9f5b90de41621a58c6
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Aug 16 09:57:17 2025 +0100
FAQ: update website/hosting/forges section.
The question about a nicer domain name, with answer "we don't want
one", is very out of date now that we actually have one! Also, the
section about putty.org wants updating after the recent drama. While I
was there I decided the Sourceforge question was too old to live, and
replaced it with some more up-to-date thoughts about forges in general
and Github in particular.
The new question faq-putty-org-pivot ("putty.org became weird kookery,
have you been hacked or bought out?") is frequently asked in the sense
that I've seen it twice in the past week or two: once in email, and
once on Mastodon (though someone quickly posted the right answer in
response).
While I'm here, it seems a bit pointless these days for faq-link to
explain the Google pagerank system to everyone. It's been a long time
since Google Search was new enough that it needed explaining, and in
any case, I've no idea if it's still accurate any more!
commit 2a5f604ffae817b4639adaac17569399c4d45de0
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Aug 16 09:56:40 2025 +0100
Makefile rules for icons used on putty.software.
Various web design guidelines asked for an assortment of larger sizes
of PNG to link to in various ways, with and without transparency.
commit 580ab2604dcb65fdb0e700e04be19ce8e671dc35
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Aug 1 12:33:04 2025 +0100
HTTP proxy digest auth: tolerate multiple qop options.
We were rejecting any 'Proxy-Authenticate: Digest' header from the
proxy if the 'qop' setting was not exactly the string "auth", which is
the only quality of protection that this code supports. However 'qop'
is supposed to be a _list_ of possibilities, so we should also be
happy if the proxy presents a list of more than one option, as long as
"auth" is one of them.
commit 2eee88480aedaa85079c86179743237c74643492
Author: Simon Tatham <anakin@pobox.com>
Date: Thu Jul 31 12:49:23 2025 +0100
Windows: fix stale-netevent problem in the CLI tools.
This fixes in the CLI tools – Plink and friends – the same bug fixed
by the recent commit bb8894ff12f9175: if an HTTP proxy demands
authentication via a 407 response with Connection: close, then PuTTY
immediately makes a second connection to the proxy, which (often)
reuses the same socket id at the Win32 API layer, and then a lingering
activity notification for the previous socket confuses the handling of
the new one.
My entire diagnosis and fix in the previous commit were completely
derived from reasoning about window message queues and WSAAsyncSelect,
so I jumped to the conclusion that the problem would be specific to
the GUI tools, which are the ones that _use_ WSAAsyncSelect. But I
didn't actually test with Plink. When I did, it turns out that for a
completely different reason, cliloop.c has an isomorphic bug, causing
the same symptom by a different route.
In the CLI tools, instead of WSAAsyncSelect, we use WSAEventSelect, in
which Windows signals an event object when socket activity happens. We
respond by calling WSAEnumNetworkEvents, which tells us what kind of
activity it was, as a bitmap of FD_READ, FD_WRITE, FD_CLOSE etc. Then
we iterate over those bits in a particular order, processing each one
with a call to select_result().
In this case, the problem wasn't anything lingering in a _queue_. It
was simply that we call select_result() to process an FD_READ
notification for the socket, which closes the socket and makes a new
one, and then select_result() returns to the for-loop which is still
iterating over the bit mask returned from WSAEnumNetworkEvents, so in
the next loop iteration it tries to process the FD_CLOSE notification
for the old socket, not realising that the socket went away in the
meantime.
I've fixed this by the brute-force technique of moving all the
select_result calls out of the for-loop completely. Now cliloop.c does
the same thing as select-gui.c: it schedules each instance of handling
socket activity as a toplevel callback, and the callbacks don't
actually _happen_ until we've completely finished handling the
signalled event object. So now, when we're handling FD_READ and still
have FD_CLOSE left in a queue somewhere, the queue is the toplevel
callback system instead of a for-loop further up the call stack – and
that means we can clear the queue via delete_callbacks() in the same
way that the previous commit did it for the GUI tools.
# This is the commit message #2:
# fixup! Windows: fix stale-netevent problem in the CLI tools.
commit 3cbe8522a0339d39eaad212d050c4930b23cc767
Author: Simon Tatham <anakin@pobox.com>
Date: Thu Jul 31 12:51:37 2025 +0100
Windows: fix memory leak in the stale-netevent fix.
When we delete toplevel callbacks for a defunct socket, we must also
free the tiny parameter structure we allocated for each one.
commit bb8894ff12f9175d8ebc2c0efe2b56a72f091878
Author: Simon Tatham <anakin@pobox.com>
Date: Thu Jul 24 08:36:36 2025 +0100
Windows: clear pending netevents when closing a socket.
I hope that this fixes http-proxy-auth-wsaenotconn, although I've only
tested it on a hacked-up Python tool that mimics a web proxy only far
enough to reproduce the issue, and haven't confirmed a successful
connection through a working HTTP proxy.
Background: the GUI network tools (both PuTTY and Pageant – anything
that links with select-gui.c) use the WSAAsyncSelect method of
reporting socket activity, which sends a window message to a nominated
HWND when activity happens on a socket. When we receive one of those
messages, we don't handle it synchronously in WndProc: instead we
queue a toplevel callback, and deal with the network activity when the
callbacks are next run from the main loop.
This means that when we _close_ a socket, there are two possible
places where unhandled notifications for the old socket might still be
lurking around. They might be in our window's message queue waiting
for GetMessage to retrieve them, or they might have been moved from
there into the toplevel callback queue.
Either way, this is a source of potential bugs, because WinSock
eagerly reuses numeric socket IDs: it's entirely possible in practice
to close a socket, immediately open another one, and find the new
socket has reused the old one's ID. Then those unhandled notifications
don't just refer to a nonexistent socket any more: instead, they
misleadingly look as if they refer to the _new_ socket, and cause
bugs.
The case of this that comes up in practice, described in
http-proxy-auth-wsaenotconn, involves an HTTP proxy sending a 407
Proxy Authentication Required response with Connection: close. In that
situation, PuTTY wants to try again with authentication, but since
that TCP connection is going away, it must make a fresh connection to
the proxy for the retry. So it does close the socket and open a new
one within the same event handler, and the old socket ID is often
reused for the new socket, and a lingering FD_CLOSE notification from
the old socket causes PuTTY to incorrectly believe that the proxy has
slammed the _new_ connection shut.
According to my diagnostics, this particular FD_CLOSE notification
generally seems to have been moved from the window message queue into
a pending toplevel callback. But the other failure mode is possible in
principle too – perhaps more likely in cases where you close a socket
in response to some other window message. So we should deal with both.
In this commit, I deal with stale toplevel callbacks by using the new
delete_callbacks() function introduced in the previous commit, which
takes a predicate function to decide whether to delete each callback.
That lets me distinguish WM_NETEVENT callbacks citing a particular
socket.
Dealing with stale window messages is harder, because as far as I can
tell, there's no Win32 API to trawl the message queue deleting a
subset of messages of this kind. (GetMessage and PeekMessage both have
wMsgFilterMin and wMsgFilterMax parameters which can filter by the
message type, but to narrow down to just one socket, we would also
need to filter on wParam, and there's no call for that.)
So instead I do a nasty bodge. Wherever we call closesocket(),
select-gui.c posts itself a new custom message WM_DONE_WITH_SOCKET,
which goes on to the end of the message queue, and acts as a dividing
line. Any WM_NETEVENT seen for that socket id _before_
WM_DONE_WITH_SOCKET was already in the queue at the time we called
closesocket(), and therefore refers to the old socket and should be
ignored; but WM_NETEVENTs for the same id _after_ WM_DONE_WITH_SOCKET
must refer to some new socket reusing the id, and should be handled
normally. So select-gui.c keeps a tree234 of "moribund" socket ids:
ones for which we've posted a WM_DONE_WITH_SOCKET message to ourself
but not yet got it back, and therefore, until we do, WM_NETEVENTs
should be ignored.
commit b7db18690b518dc0e9d668bb50c81b485ea449ba
Author: Simon Tatham <anakin@pobox.com>
Date: Fri Jul 25 08:28:53 2025 +0100
More general function to delete toplevel callbacks.
For cases where you want a more subtle criterion than "cites this
particular context structure". I'm going to introduce one in the next
commit.
commit edce58d49dfa17586b2f407fd668dd4dcc41496b
Author: Simon Tatham <anakin@pobox.com>
Date: Sat Jul 26 09:59:55 2025 +0100
HTTP proxy: fix misspelled error message (and comment).
A 407 response from the proxy is expected to contain at least one
header naming an acceptable authentication method. The header name is
"Proxy-Authenticate". But if no such header is seen, our error message
incorrectly spelled the missing header name as "Proxy-Authorization".
That's a braino rather than a typo: "Proxy-Authorization" is the
header the _client_ sends for an actual attempt to authenticate.
commit 0c5fd787135608dc55cc13418ef37cc00236ed64
Author: Simon Tatham <anakin@pobox.com>
Date: Thu Jul 24 08:18:10 2025 +0100
GTK: stop using GDK_CURRENT_TIME.
gtk_get_current_event_time() is better: it returns the X server
timestamp associated with any event currently being handled. And if
there isn't one, it falls back to returning GDK_CURRENT_TIME, so it
doesn't do any worse than hardcoding GDK_CURRENT_TIME did.
commit 26a8ef376daf5f50c441a65691b84f87df49db9b
Author: Simon Tatham <anakin@pobox.com>
Date: Wed Jun 25 13:02:56 2025 +0100
Fix crash in utmp-stamping on Wayland.
Thanks to Colin Watson for the report: if pterm is both
able (appropriately setgid) and willing (given the right options) to
stamp utmp, it will use $DISPLAY as the location to write into utmp,
and segfault if it's not set. But in a Wayland-only system it might
very well not be set.
To fix this I've generalised seat_get_x_display() into
seat_get_display(), so that it can also return a display id string
like "wayland-0" if that's what's appropriate. So now in that
situation pterm will stamp utmp with a Wayland display id in place of
an X11 one.
However, seat_get_x_display() was also used to retrieve an X11 display
name specifically so as to populate $DISPLAY in the terminal's shell.
So the new seat_get_display() has a parameter to constrain the
returned display to be of a particular type, or NULL if that type
isn't available.
As a final fallback, in case seat_get_display(seat, SDISP_ANY) might
_still_ manage to return NULL for any reason, we catch that and turn
it into the empty string before stamping utmp, so that we still won't
segfault.
There are 3 open security issues in trixie.
You can find information about how to handle these issues in the security team's documentation.
There are 3 open security issues in bookworm.
You can find information about how to handle these issues in the security team's documentation.