Skip to content

Review - EXPECT-100-CL #113

Closed
Closed

Description

@remittor

Doc: https://www.http-probe.com/docs/smuggling/expect-100-cl/

The documentation states that if the server has received the body and headers, it may not send the "HTTP/1.1 100 CONTINUE" message to the client.
This is a profound misconception on the part of the people writing the standards. They're far removed from programming!
They forgot that packets can be fragmented along the way.
And even if the client sent the body along with the "Expect: 100-continue" header, a situation could still arise where the server first reads from the pending socket (the first recv call) and only then the request body (the second recv call). The standard writers didn't see this coming!

So the server should always send an "HTTP/1.1 100 CONTINUE" response, so as not to violate the standard!

Activity

  1. MDA2AV commented on Apr 6, 2026

    @MDA2AV
    Owner

    Well, in case of fragmentation it is possible that the client sends the body and still receives a 100 continue response.

    In this test suite the fragmentation is guaranteed to not happen.

    Expect 100 is a known source of request smuggling vectors due to its inherent behavior issues.

    This test simply focus on a simple case when the header is sent with the body with no fragmentation

  2. remittor commented on Apr 6, 2026

    @remittor
    ContributorAuthor

    This test simply focus on a simple case when the header is sent with the body with no fragmentation

    You don't understand what I'm talking about!
    There's a serious error in the standard description!
    The creators of the standard forgot that HTTP/1.1 occurs within a TCP stream, which requires explicitly passing some kind of flag between different messages. It's not a datagram (UDP), where requests can be controlled on both sides at the send and recv call level.

    Therefore, when receiving a header "Expect: 100-continue", the server must in all cases first respond with "HTTP/1.1 100 CONTINUE" and then send a full response.

  3. MDA2AV commented on Apr 6, 2026

    @MDA2AV
    Owner

    Not if you receive the full content from the first stream read, in that case the server already has the whole request and does not need to bother to send a 100 CONTINUE, at all the other times the server should send 100 CONTINUE (no content or incomplete)

    a 100, 4xx or 200 should all be acceptable here, maybe 4xx is questionable but I can accept a server doesnt want to deal with 100 bullshit

  4. MDA2AV commented on Apr 6, 2026

    @MDA2AV
    Owner

    The purpose of most these tests are not to validate whether a framework follows RFC but to see difference in behavior between frameworks, that is where the true problem and valuable information for an attacker is, the goal of this smuggling category is to create scenarios where frameworks behave very differently, opening attack vectors when they are combined in a reverse proxy

  5. remittor commented on Apr 6, 2026

    @remittor
    ContributorAuthor

    Not if you receive the full content from the first stream read, in that case the server already has the whole request and does not need to bother to send a 100 CONTINUE, at all the other times the server should send 100 CONTINUE (no content or incomplete)

    The client can't know in advance whether the server will receive the request headers and body in a single data block!!!
    On the way to the server, this data block may be split exactly between the headers and the request body. The server will receive the headers first, and then, after N milliseconds, the request body. In this case, the server (following the standard) will first send "HTTP/1.1 100 CONTINUE" to the client.
    But the client doesn't expect "HTTP/1.1 100 CONTINUE" before the response body, since it sent the entire TCP stream as a single block.

    Now do you understand what I'm talking about?

  6. MDA2AV commented on Apr 6, 2026

    @MDA2AV
    Owner

    Now do you understand what I'm talking about?

    I understand what you mean from the beginning and that is not a server issue, the client needs to handle that because from the server perspective it can't guess whether be body is coming or not and needs to send a 100 CONTINUE anyway.

    BUT in this test on this suite the client is guaranteed to receive the full request at once, there is no fragmentation possible here, this is a controlled environment scenario, we guarantee the client always sees the full body which means we expect a 200 or a 4xx if he doesn't allow 100 in requests. As I said we can accept a server responding a 100 too as it can happen in the wild that the server doesn't see the body due to fragmentation or other issues.

    A server can send both 100 CONTINUE, 200 or 4xx here. this is the update I agree on

    What is your suggestion, only 100?

  7. remittor commented on Apr 6, 2026

    @remittor
    ContributorAuthor

    What is your suggestion, only 100?

    My server always sends 100 and then 200. And this test doesn't like this behavior, because it just stupidly follows the standard with a bug.

  8. remittor commented on Apr 6, 2026

    @remittor
    ContributorAuthor

    I just now noticed that this test is unscored ;-)

  9. MDA2AV commented on Apr 6, 2026

    @MDA2AV
    Owner

    What is your suggestion, only 100?

    My server always sends 100 and then 200. And this test doesn't like this behavior, because it just stupidly follows the standard with a bug.

    I agree 100 should be accepted :) I will change that

  10. MDA2AV commented on Apr 6, 2026

    @MDA2AV
    Owner

    I just now noticed that this test is unscored ;-)

    Unscored tests means that I am open to change in this case, and in some cases mean that the RFC is too ambiguous and we can't score server based on it so it simply serves as information

  11. MDA2AV commented on Apr 22, 2026

    @MDA2AV
    Owner

    Fixed with #119

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions