From 6de982d910f9a65d9af659a7024bbe1b42f7078b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 10 Jun 2026 11:39:55 +0900 Subject: [PATCH] Reject CR/LF in POP3 command arguments The account and password supplied to USER, PASS, and APOP were interpolated into command lines and written to the socket without neutralizing CR/LF, so an application forwarding untrusted input as login arguments could inject arbitrary POP3 commands. This mirrors the validate_line guard already present in net-smtp and net-ftp. As with the net-http change, the affected inputs come from the application itself, so this is treated as a bug rather than a vulnerability. Reported-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 --- lib/net/pop.rb | 11 +++++++++-- test/net/pop/test_pop.rb | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/net/pop.rb b/lib/net/pop.rb index d4ee8f8..af4948c 100644 --- a/lib/net/pop.rb +++ b/lib/net/pop.rb @@ -984,15 +984,22 @@ def quit private def getok(fmt, *fargs) - @socket.writeline sprintf(fmt, *fargs) + @socket.writeline validate_line(sprintf(fmt, *fargs)) check_response(recv_response()) end def get_response(fmt, *fargs) - @socket.writeline sprintf(fmt, *fargs) + @socket.writeline validate_line(sprintf(fmt, *fargs)) recv_response() end + def validate_line(line) + if /[\r\n]/.match?(line) + raise ArgumentError, "POP3 command cannot include CR/LF" + end + line + end + def recv_response @socket.readline end diff --git a/test/net/pop/test_pop.rb b/test/net/pop/test_pop.rb index f4c807a..a48d178 100644 --- a/test/net/pop/test_pop.rb +++ b/test/net/pop/test_pop.rb @@ -64,6 +64,30 @@ def test_apop_invalid_at end end + def test_pop_user_crlf_injection + pop_test(false) do |pop| + assert_raise ArgumentError do + pop.start("user\r\nDELE 1", @users[@ok_user]) + end + end + end + + def test_pop_pass_crlf_injection + pop_test(false) do |pop| + assert_raise ArgumentError do + pop.start(@ok_user, "pass\r\nDELE 1") + end + end + end + + def test_apop_crlf_injection + pop_test(@stamp_base) do |pop| + assert_raise ArgumentError do + pop.start("user\r\nDELE 1", @users[@ok_user]) + end + end + end + def test_popmail # totally not representative of real messages, but # enough to test frozen bugs