VYPR
Moderate severityNVD Advisory· Published May 6, 2014· Updated May 6, 2026

CVE-2014-0193

CVE-2014-0193

Description

WebSocket08FrameDecoder in Netty 3.6.x before 3.6.9, 3.7.x before 3.7.1, 3.8.x before 3.8.2, 3.9.x before 3.9.1, and 4.0.x before 4.0.19 allows remote attackers to cause a denial of service (memory consumption) via a TextWebSocketFrame followed by a long stream of ContinuationWebSocketFrames.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
io.netty:nettyMaven
>= 3.6.0.Beta1, < 3.6.9.Final3.6.9.Final
io.netty:nettyMaven
>= 3.7.0.Final, < 3.7.1.Final3.7.1.Final
io.netty:nettyMaven
>= 3.8.0.Final, < 3.8.2.Final3.8.2.Final
io.netty:nettyMaven
>= 3.9.0.Final, < 3.9.1.Final3.9.1.Final
io.netty:nettyMaven
>= 4.0.0.Alpha1, < 4.0.19.Final4.0.19.Final
io.netty:netty-allMaven
>= 4.0.0.Alpha1, < 4.0.19.Final4.0.19.Final

Affected products

32
  • Netty/Netty32 versions
    cpe:2.3:a:netty:netty:3.6.0:*:*:*:*:*:*:*+ 31 more
    • cpe:2.3:a:netty:netty:3.6.0:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.1:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.2:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.3:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.4:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.5:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.6:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.7:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.6.8:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.7.0:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.8.0:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.8.1:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:3.9.0:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.3:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.4:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.5:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.6:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.7:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.8:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.9:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.10:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.11:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.12:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.13:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.14:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.15:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.16:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.17:*:*:*:*:*:*:*
    • cpe:2.3:a:netty:netty:4.0.18:*:*:*:*:*:*:*

Patches

1
8599ab5bdb76

Remove ContinuationWebSocketFrame.aggregatedText()

https://github.com/netty/nettyNorman MaurerApr 30, 2014via ghsa
4 files changed · +49 130
  • codec-http/src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java+4 32 modified
    @@ -25,13 +25,11 @@
      */
     public class ContinuationWebSocketFrame extends WebSocketFrame {
     
    -    private String aggregatedText;
    -
         /**
          * Creates a new empty continuation frame.
          */
         public ContinuationWebSocketFrame() {
    -        super(Unpooled.buffer(0));
    +        this(Unpooled.buffer(0));
         }
     
         /**
    @@ -58,25 +56,6 @@ public ContinuationWebSocketFrame(boolean finalFragment, int rsv, ByteBuf binary
             super(finalFragment, rsv, binaryData);
         }
     
    -    /**
    -     * Creates a new continuation frame with the specified binary data
    -     *
    -     * @param finalFragment
    -     *            flag indicating if this frame is the final fragment
    -     * @param rsv
    -     *            reserved bits used for protocol extensions
    -     * @param binaryData
    -     *            the content of the frame.
    -     * @param aggregatedText
    -     *            Aggregated text set by decoder on the final continuation frame of a fragmented
    -     *            text message
    -     */
    -    public ContinuationWebSocketFrame(
    -            boolean finalFragment, int rsv, ByteBuf binaryData, String aggregatedText) {
    -        super(finalFragment, rsv, binaryData);
    -        this.aggregatedText = aggregatedText;
    -    }
    -
         /**
          * Creates a new continuation frame with the specified text data
          *
    @@ -88,7 +67,7 @@ public ContinuationWebSocketFrame(
          *            text content of the frame.
          */
         public ContinuationWebSocketFrame(boolean finalFragment, int rsv, String text) {
    -        this(finalFragment, rsv, fromText(text), null);
    +        this(finalFragment, rsv, fromText(text));
         }
     
         /**
    @@ -112,21 +91,14 @@ private static ByteBuf fromText(String text) {
             }
         }
     
    -    /**
    -     * Aggregated text returned by decoder on the final continuation frame of a fragmented text message
    -     */
    -    public String aggregatedText() {
    -        return aggregatedText;
    -    }
    -
         @Override
         public ContinuationWebSocketFrame copy() {
    -        return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content().copy(), aggregatedText());
    +        return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content().copy());
         }
     
         @Override
         public ContinuationWebSocketFrame duplicate() {
    -        return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content().duplicate(), aggregatedText());
    +        return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content().duplicate());
         }
     
         @Override
    
  • codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java+0 47 removed
    @@ -1,47 +0,0 @@
    -/*
    - * Copyright 2012 The Netty Project
    - *
    - * The Netty Project licenses this file to you under the Apache License,
    - * version 2.0 (the "License"); you may not use this file except in compliance
    - * with the License. You may obtain a copy of the License at:
    - *
    - *   http://www.apache.org/licenses/LICENSE-2.0
    - *
    - * Unless required by applicable law or agreed to in writing, software
    - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    - * License for the specific language governing permissions and limitations
    - * under the License.
    - */
    -/*
    - * Adaptation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
    - *
    - * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
    - *
    - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    - * and associated documentation files (the "Software"), to deal in the Software without restriction,
    - * including without limitation the rights to use, copy, modify, merge, publish, distribute,
    - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
    - * furnished to do so, subject to the following conditions:
    - *
    - * The above copyright notice and this permission notice shall be included in all copies or
    - * substantial portions of the Software.
    - *
    - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    - */
    -package io.netty.handler.codec.http.websocketx;
    -
    -/**
    - * Invalid UTF8 bytes encountered
    - */
    -final class UTF8Exception extends RuntimeException {
    -    private static final long serialVersionUID = 1L;
    -
    -    UTF8Exception(String reason) {
    -        super(reason);
    -    }
    -}
    
  • codec-http/src/main/java/io/netty/handler/codec/http/websocketx/Utf8Validator.java+22 27 renamed
    @@ -36,11 +36,13 @@
     package io.netty.handler.codec.http.websocketx;
     
     import io.netty.buffer.ByteBuf;
    +import io.netty.buffer.ByteBufProcessor;
    +import io.netty.handler.codec.CorruptedFrameException;
     
     /**
    - * Checks UTF8 bytes for validity before converting it into a string
    + * Checks UTF8 bytes for validity
      */
    -final class UTF8Output {
    +final class Utf8Validator implements ByteBufProcessor {
         private static final int UTF8_ACCEPT = 0;
         private static final int UTF8_REJECT = 12;
     
    @@ -65,45 +67,38 @@ final class UTF8Output {
         @SuppressWarnings("RedundantFieldInitialization")
         private int state = UTF8_ACCEPT;
         private int codep;
    +    private boolean checking;
     
    -    private final StringBuilder stringBuilder;
    -
    -    UTF8Output(ByteBuf buffer) {
    -        stringBuilder = new StringBuilder(buffer.readableBytes());
    -        write(buffer);
    +    public void check(ByteBuf buffer) {
    +        checking = true;
    +        buffer.forEachByte(this);
         }
     
    -    public void write(ByteBuf buffer) {
    -        for (int i = buffer.readerIndex(); i < buffer.writerIndex(); i++) {
    -            write(buffer.getByte(i));
    -        }
    -    }
    -
    -    public void write(byte[] bytes) {
    -        for (byte b : bytes) {
    -            write(b);
    +    public void finish() {
    +        checking = false;
    +        codep = 0;
    +        if (state != UTF8_ACCEPT) {
    +            state = UTF8_ACCEPT;
    +            throw new CorruptedFrameException("bytes are not UTF-8");
             }
         }
     
    -    public void write(int b) {
    +    @Override
    +    public boolean process(byte b) throws Exception {
             byte type = TYPES[b & 0xFF];
     
             codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
     
             state = STATES[state + type];
     
    -        if (state == UTF8_ACCEPT) {
    -            stringBuilder.append((char) codep);
    -        } else if (state == UTF8_REJECT) {
    -            throw new UTF8Exception("bytes are not UTF-8");
    +        if (state == UTF8_REJECT) {
    +            checking = false;
    +            throw new CorruptedFrameException("bytes are not UTF-8");
             }
    +        return true;
         }
     
    -    @Override
    -    public String toString() {
    -        if (state != UTF8_ACCEPT) {
    -            throw new UTF8Exception("bytes are not UTF-8");
    -        }
    -        return stringBuilder.toString();
    +    public boolean isChecking() {
    +        return checking;
         }
     }
    
  • codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java+23 24 modified
    @@ -92,7 +92,10 @@ enum State {
         private static final byte OPCODE_PING = 0x9;
         private static final byte OPCODE_PONG = 0xA;
     
    -    private UTF8Output fragmentedFramesText;
    +    private final long maxFramePayloadLength;
    +    private final boolean allowExtensions;
    +    private final boolean maskedPayload;
    +
         private int fragmentedFramesCount;
         private boolean frameFinalFlag;
         private int frameRsv;
    @@ -101,11 +104,7 @@ enum State {
         private byte[] maskingKey;
         private int framePayloadLen1;
         private boolean receivedClosingHandshake;
    -
    -    private final long maxFramePayloadLength;
    -    private final boolean allowExtensions;
    -    private final boolean maskedPayload;
    -
    +    private Utf8Validator utf8Validator;
         private State state = State.READING_FIRST;
     
         /**
    @@ -311,37 +310,34 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) t
     
                             // Processing for possible fragmented messages for text and binary
                             // frames
    -                        String aggregatedText = null;
                             if (frameFinalFlag) {
                                 // Final frame of the sequence. Apparently ping frames are
                                 // allowed in the middle of a fragmented message
                                 if (frameOpcode != OPCODE_PING) {
                                     fragmentedFramesCount = 0;
     
                                     // Check text for UTF8 correctness
    -                                if (frameOpcode == OPCODE_TEXT || fragmentedFramesText != null) {
    +                                if (frameOpcode == OPCODE_TEXT ||
    +                                        (utf8Validator != null && utf8Validator.isChecking())) {
                                         // Check UTF-8 correctness for this payload
                                         checkUTF8String(ctx, payloadBuffer);
     
                                         // This does a second check to make sure UTF-8
                                         // correctness for entire text message
    -                                    aggregatedText = fragmentedFramesText.toString();
    -
    -                                    fragmentedFramesText = null;
    +                                    utf8Validator.finish();
                                     }
                                 }
                             } else {
                                 // Not final frame so we can expect more frames in the
                                 // fragmented sequence
                                 if (fragmentedFramesCount == 0) {
                                     // First text or binary frame for a fragmented set
    -                                fragmentedFramesText = null;
                                     if (frameOpcode == OPCODE_TEXT) {
                                         checkUTF8String(ctx, payloadBuffer);
                                     }
                                 } else {
                                     // Subsequent frames - only check if init frame is text
    -                                if (fragmentedFramesText != null) {
    +                                if (utf8Validator != null && utf8Validator.isChecking()) {
                                         checkUTF8String(ctx, payloadBuffer);
                                     }
                                 }
    @@ -361,7 +357,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) t
                                 return;
                             } else if (frameOpcode == OPCODE_CONT) {
                                 out.add(new ContinuationWebSocketFrame(frameFinalFlag, frameRsv,
    -                                    payloadBuffer, aggregatedText));
    +                                    payloadBuffer));
                                 payloadBuffer = null;
                                 return;
                             } else {
    @@ -392,11 +388,15 @@ private void unmask(ByteBuf frame) {
         }
     
         private void protocolViolation(ChannelHandlerContext ctx, String reason) {
    +        protocolViolation(ctx, new CorruptedFrameException(reason));
    +    }
    +
    +    private void protocolViolation(ChannelHandlerContext ctx, CorruptedFrameException ex) {
             state = State.CORRUPT;
             if (ctx.channel().isActive()) {
                 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
             }
    -        throw new CorruptedFrameException(reason);
    +        throw ex;
         }
     
         private static int toFrameLength(long l) {
    @@ -409,13 +409,12 @@ private static int toFrameLength(long l) {
     
         private void checkUTF8String(ChannelHandlerContext ctx, ByteBuf buffer) {
             try {
    -            if (fragmentedFramesText == null) {
    -                fragmentedFramesText = new UTF8Output(buffer);
    -            } else {
    -                fragmentedFramesText.write(buffer);
    +            if (utf8Validator == null) {
    +                utf8Validator = new Utf8Validator();
                 }
    -        } catch (UTF8Exception ex) {
    -            protocolViolation(ctx, "invalid UTF-8 bytes");
    +            utf8Validator.check(buffer);
    +        } catch (CorruptedFrameException ex) {
    +            protocolViolation(ctx, ex);
             }
         }
     
    @@ -443,9 +442,9 @@ protected void checkCloseFrameBody(
             // May have UTF-8 message
             if (buffer.isReadable()) {
                 try {
    -                new UTF8Output(buffer);
    -            } catch (UTF8Exception ex) {
    -                protocolViolation(ctx, "Invalid close frame reason text. Invalid UTF-8 bytes");
    +                new Utf8Validator().check(buffer);
    +            } catch (CorruptedFrameException ex) {
    +                protocolViolation(ctx, ex);
                 }
             }
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

21

News mentions

0

No linked articles in our index yet.