Skip to content

Commit 920e1ca

Browse files
committed
fix: preserve value in t:base64Decode when input is not valid base64
Replace broken decode(string) with decode(string, string&) that checks the mbedtls return value. On invalid input, the original value is now preserved and transform returns false. Updated all callers including remote_user.cc.
1 parent e5d00df commit 920e1ca

4 files changed

Lines changed: 36 additions & 8 deletions

File tree

src/actions/transformations/base64_decode.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ namespace modsecurity::actions::transformations {
2323

2424
bool Base64Decode::transform(std::string &value, const Transaction *trans) const {
2525
if (value.empty()) return false;
26-
value = Utils::Base64::decode(value);
26+
27+
std::string decoded;
28+
if (!Utils::Base64::decode(value, decoded)) {
29+
return false;
30+
}
31+
32+
value = std::move(decoded);
2733
return true;
2834
}
2935

30-
3136
} // namespace modsecurity::actions::transformations

src/utils/base64.cc

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,33 @@ std::string Base64::decode(const std::string& data, bool forgiven) {
5555
return decode_forgiven(data);
5656
}
5757

58-
return decode(data);
58+
std::string out;
59+
decode(data, out);
60+
return out;
5961
}
6062

6163

62-
std::string Base64::decode(const std::string& data) {
63-
return base64Helper(data.c_str(), strlen(data.c_str()), mbedtls_base64_decode);
64-
}
64+
bool Base64::decode(const std::string& data, std::string &out) {
65+
size_t out_len = 0;
66+
const auto *src = reinterpret_cast<const unsigned char *>(data.c_str());
67+
const size_t slen = strlen(data.c_str());
68+
69+
const int ret = mbedtls_base64_decode(nullptr, 0, &out_len, src, slen);
70+
71+
if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
72+
return false;
73+
}
74+
75+
out.resize(out_len);
76+
if (mbedtls_base64_decode(
77+
reinterpret_cast<unsigned char *>(out.data()),
78+
out.size(), &out_len, src, slen) != 0) {
79+
return false;
80+
}
6581

82+
out.resize(out_len);
83+
return true;
84+
}
6685

6786
std::string Base64::decode_forgiven(const std::string& data) {
6887
return base64Helper(data.c_str(), data.size(), decode_forgiven_engine);

src/utils/base64.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Base64 {
2929
static std::string encode(const std::string& data);
3030

3131
static std::string decode(const std::string& data, bool forgiven);
32-
static std::string decode(const std::string& data);
32+
static bool decode(const std::string& data, std::string &out);
3333
static std::string decode_forgiven(const std::string& data);
3434

3535
static void decode_forgiven_engine(unsigned char *plain_text,

src/variables/remote_user.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ void RemoteUser::evaluate(Transaction *transaction,
5454
base64 = std::string(header, 6, header.length());
5555
}
5656

57-
base64 = Utils::Base64::decode(base64);
57+
std::string decoded;
58+
59+
if (Utils::Base64::decode(base64, decoded)) {
60+
base64 = std::move(decoded);
61+
}
5862

5963
if (const auto pos{base64.find(":")}; pos != std::string::npos) {
6064
transaction->m_variableRemoteUser.assign(std::string(base64, 0, pos));

0 commit comments

Comments
 (0)