Skip to content

Commit

Permalink
Make prototype pollution attacks harder in most Bun APIs that accept …
Browse files Browse the repository at this point in the history
…objects (#14119)
  • Loading branch information
Jarred-Sumner authored Sep 25, 2024
1 parent 2856267 commit 5722ae8
Show file tree
Hide file tree
Showing 24 changed files with 405 additions and 245 deletions.
2 changes: 1 addition & 1 deletion src/bun.js/ConsoleObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ pub const Formatter = struct {

// Is this a react element?
if (js_type.isObject()) {
if (value.get(globalThis, "$$typeof")) |typeof_symbol| {
if (value.getOwnTruthy(globalThis, "$$typeof")) |typeof_symbol| {
var reactElement = ZigString.init("react.element");
var react_fragment = ZigString.init("react.fragment");

Expand Down
32 changes: 16 additions & 16 deletions src/bun.js/api/BunObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -475,11 +475,11 @@ pub fn braces(
if (arguments.nextEat()) |opts_val| {
if (opts_val.isObject()) {
if (comptime bun.Environment.allow_assert) {
if (opts_val.getTruthy(globalThis, "tokenize")) |tokenize_val| {
if (opts_val.getOwnTruthy(globalThis, "tokenize")) |tokenize_val| {
tokenize = if (tokenize_val.isBoolean()) tokenize_val.asBoolean() else false;
}

if (opts_val.getTruthy(globalThis, "parse")) |tokenize_val| {
if (opts_val.getOwnTruthy(globalThis, "parse")) |tokenize_val| {
parse = if (tokenize_val.isBoolean()) tokenize_val.asBoolean() else false;
}
}
Expand Down Expand Up @@ -607,11 +607,11 @@ pub fn which(

if (arguments.nextEat()) |arg| {
if (!arg.isEmptyOrUndefinedOrNull() and arg.isObject()) {
if (arg.get(globalThis, "PATH")) |str_| {
if (arg.getOwn(globalThis, "PATH")) |str_| {
path_str = str_.toSlice(globalThis, globalThis.bunVM().allocator);
}

if (arg.get(globalThis, "cwd")) |str_| {
if (arg.getOwn(globalThis, "cwd")) |str_| {
cwd_str = str_.toSlice(globalThis, globalThis.bunVM().allocator);
}
}
Expand Down Expand Up @@ -660,7 +660,7 @@ pub fn inspect(
const arg1 = arguments[1];

if (arg1.isObject()) {
if (arg1.getTruthy(globalThis, "depth")) |opt| {
if (arg1.getOwnTruthy(globalThis, "depth")) |opt| {
if (opt.isInt32()) {
const arg = opt.toInt32();
if (arg < 0) {
Expand Down Expand Up @@ -932,7 +932,7 @@ pub fn openInEditor(

if (arguments.nextEat()) |opts| {
if (!opts.isUndefinedOrNull()) {
if (opts.getTruthy(globalThis, "editor")) |editor_val| {
if (opts.getOwnTruthy(globalThis, "editor")) |editor_val| {
var sliced = editor_val.toSlice(globalThis, arguments.arena.allocator());
const prev_name = edit.name;

Expand All @@ -952,11 +952,11 @@ pub fn openInEditor(
}
}

if (opts.getTruthy(globalThis, "line")) |line_| {
if (opts.getOwnTruthy(globalThis, "line")) |line_| {
line = line_.toSlice(globalThis, arguments.arena.allocator()).slice();
}

if (opts.getTruthy(globalThis, "column")) |column_| {
if (opts.getOwnTruthy(globalThis, "column")) |column_| {
column = column_.toSlice(globalThis, arguments.arena.allocator()).slice();
}
}
Expand Down Expand Up @@ -1828,7 +1828,7 @@ pub const Crypto = struct {

pub fn fromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) ?Value {
if (value.isObject()) {
if (value.getTruthy(globalObject, "algorithm")) |algorithm_value| {
if (value.getOwnTruthy(globalObject, "algorithm")) |algorithm_value| {
if (!algorithm_value.isString()) {
globalObject.throwInvalidArgumentType("hash", "algorithm", "string");
return null;
Expand All @@ -1845,7 +1845,7 @@ pub const Crypto = struct {
.bcrypt = PasswordObject.Algorithm.Value.bcrpyt_default,
};

if (value.getTruthy(globalObject, "cost")) |rounds_value| {
if (value.getOwnTruthy(globalObject, "cost")) |rounds_value| {
if (!rounds_value.isNumber()) {
globalObject.throwInvalidArgumentType("hash", "cost", "number");
return null;
Expand All @@ -1866,7 +1866,7 @@ pub const Crypto = struct {
inline .argon2id, .argon2d, .argon2i => |tag| {
var argon = Algorithm.Argon2Params{};

if (value.getTruthy(globalObject, "timeCost")) |time_value| {
if (value.getOwnTruthy(globalObject, "timeCost")) |time_value| {
if (!time_value.isNumber()) {
globalObject.throwInvalidArgumentType("hash", "timeCost", "number");
return null;
Expand All @@ -1882,7 +1882,7 @@ pub const Crypto = struct {
argon.time_cost = @as(u32, @intCast(time_cost));
}

if (value.getTruthy(globalObject, "memoryCost")) |memory_value| {
if (value.getOwnTruthy(globalObject, "memoryCost")) |memory_value| {
if (!memory_value.isNumber()) {
globalObject.throwInvalidArgumentType("hash", "memoryCost", "number");
return null;
Expand Down Expand Up @@ -4610,11 +4610,11 @@ fn stringWidth(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC
var ambiguous_as_wide = false;

if (options_object.isObject()) {
if (options_object.getTruthy(globalObject, "countAnsiEscapeCodes")) |count_ansi_escapes_value| {
if (options_object.getOwnTruthy(globalObject, "countAnsiEscapeCodes")) |count_ansi_escapes_value| {
if (count_ansi_escapes_value.isBoolean())
count_ansi_escapes = count_ansi_escapes_value.toBoolean();
}
if (options_object.getTruthy(globalObject, "ambiguousIsNarrow")) |ambiguous_is_narrow| {
if (options_object.getOwnTruthy(globalObject, "ambiguousIsNarrow")) |ambiguous_is_narrow| {
if (ambiguous_is_narrow.isBoolean())
ambiguous_as_wide = !ambiguous_is_narrow.toBoolean();
}
Expand Down Expand Up @@ -4795,7 +4795,7 @@ pub const JSZlib = struct {
library = .zlib;
}

if (options_val.getTruthy(globalThis, "library")) |library_value| {
if (options_val.getOwnTruthy(globalThis, "library")) |library_value| {
if (!library_value.isString()) {
globalThis.throwInvalidArguments("Expected library to be a string", .{});
return .zero;
Expand Down Expand Up @@ -4922,7 +4922,7 @@ pub const JSZlib = struct {
library = .zlib;
}

if (options_val.getTruthy(globalThis, "library")) |library_value| {
if (options_val.getOwnTruthy(globalThis, "library")) |library_value| {
if (!library_value.isString()) {
globalThis.throwInvalidArguments("Expected library to be a string", .{});
return .zero;
Expand Down
60 changes: 30 additions & 30 deletions src/bun.js/api/JSBundler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ pub const JSBundler = struct {
globalThis.throwInvalidArguments("Expected plugin to be an object", .{});
return error.JSError;
}
if (try plugin.getObject(globalThis, "SECRET_SERVER_COMPONENTS_INTERNALS")) |internals| {
if (internals.get(globalThis, "router")) |router_value| {
if (try plugin.getOwnObject(globalThis, "SECRET_SERVER_COMPONENTS_INTERNALS")) |internals| {
if (internals.getOwn(globalThis, "router")) |router_value| {
if (router_value.as(JSC.API.FileSystemRouter) != null) {
this.server_components.router.set(globalThis, router_value);
} else {
Expand All @@ -110,7 +110,7 @@ pub const JSBundler = struct {
}
}

const directive_object = (try internals.getObject(globalThis, "directive")) orelse {
const directive_object = (try internals.getOwnObject(globalThis, "directive")) orelse {
globalThis.throwInvalidArguments("Expected directive to be an object", .{});
return error.JSError;
};
Expand Down Expand Up @@ -154,7 +154,7 @@ pub const JSBundler = struct {
// };
// defer decl.deinit();

if (plugin.getOptional(globalThis, "name", ZigString.Slice) catch null) |slice| {
if (plugin.getOwnOptional(globalThis, "name", ZigString.Slice) catch null) |slice| {
defer slice.deinit();
if (slice.len == 0) {
globalThis.throwInvalidArguments("Expected plugin to have a non-empty name", .{});
Expand Down Expand Up @@ -198,24 +198,24 @@ pub const JSBundler = struct {
}
}

if (config.getTruthy(globalThis, "macros")) |macros_flag| {
if (config.getOwnTruthy(globalThis, "macros")) |macros_flag| {
if (!macros_flag.coerce(bool, globalThis)) {
this.no_macros = true;
}
}

if (try config.getOptionalEnum(globalThis, "target", options.Target)) |target| {
if (try config.getOwnOptionalEnum(globalThis, "target", options.Target)) |target| {
this.target = target;
}

var has_out_dir = false;
if (try config.getOptional(globalThis, "outdir", ZigString.Slice)) |slice| {
if (try config.getOwnOptional(globalThis, "outdir", ZigString.Slice)) |slice| {
defer slice.deinit();
try this.outdir.appendSliceExact(slice.slice());
has_out_dir = true;
}

if (config.getTruthy(globalThis, "sourcemap")) |source_map_js| {
if (config.getOwnTruthy(globalThis, "sourcemap")) |source_map_js| {
if (bun.FeatureFlags.breaking_changes_1_2 and config.isBoolean()) {
if (source_map_js == .true) {
this.source_map = if (has_out_dir)
Expand All @@ -232,11 +232,11 @@ pub const JSBundler = struct {
}
}

if (try config.getOptionalEnum(globalThis, "packages", options.PackagesOption)) |packages| {
if (try config.getOwnOptionalEnum(globalThis, "packages", options.PackagesOption)) |packages| {
this.packages = packages;
}

if (try config.getOptionalEnum(globalThis, "format", options.Format)) |format| {
if (try config.getOwnOptionalEnum(globalThis, "format", options.Format)) |format| {
switch (format) {
.esm => {},
else => {
Expand All @@ -246,28 +246,28 @@ pub const JSBundler = struct {
}
}

// if (try config.getOptional(globalThis, "hot", bool)) |hot| {
// if (try config.getOwnOptional(globalThis, "hot", bool)) |hot| {
// this.hot = hot;
// }

if (try config.getOptional(globalThis, "splitting", bool)) |hot| {
if (try config.getOwnOptional(globalThis, "splitting", bool)) |hot| {
this.code_splitting = hot;
}

if (config.getTruthy(globalThis, "minify")) |hot| {
if (config.getOwnTruthy(globalThis, "minify")) |hot| {
if (hot.isBoolean()) {
const value = hot.coerce(bool, globalThis);
this.minify.whitespace = value;
this.minify.syntax = value;
this.minify.identifiers = value;
} else if (hot.isObject()) {
if (try hot.getOptional(globalThis, "whitespace", bool)) |whitespace| {
if (try hot.getOwnOptional(globalThis, "whitespace", bool)) |whitespace| {
this.minify.whitespace = whitespace;
}
if (try hot.getOptional(globalThis, "syntax", bool)) |syntax| {
if (try hot.getOwnOptional(globalThis, "syntax", bool)) |syntax| {
this.minify.syntax = syntax;
}
if (try hot.getOptional(globalThis, "identifiers", bool)) |syntax| {
if (try hot.getOwnOptional(globalThis, "identifiers", bool)) |syntax| {
this.minify.identifiers = syntax;
}
} else {
Expand All @@ -291,19 +291,19 @@ pub const JSBundler = struct {
return error.JSError;
}

if (config.getTruthy(globalThis, "emitDCEAnnotations")) |flag| {
if (config.getOwnTruthy(globalThis, "emitDCEAnnotations")) |flag| {
if (flag.coerce(bool, globalThis)) {
this.emit_dce_annotations = true;
}
}

if (config.getTruthy(globalThis, "ignoreDCEAnnotations")) |flag| {
if (config.getOwnTruthy(globalThis, "ignoreDCEAnnotations")) |flag| {
if (flag.coerce(bool, globalThis)) {
this.ignore_dce_annotations = true;
}
}

if (config.getTruthy(globalThis, "conditions")) |conditions_value| {
if (config.getOwnTruthy(globalThis, "conditions")) |conditions_value| {
if (conditions_value.isString()) {
var slice = conditions_value.toSliceOrNull(globalThis) orelse {
globalThis.throwInvalidArguments("Expected conditions to be an array of strings", .{});
Expand All @@ -329,7 +329,7 @@ pub const JSBundler = struct {

{
const path: ZigString.Slice = brk: {
if (try config.getOptional(globalThis, "root", ZigString.Slice)) |slice| {
if (try config.getOwnOptional(globalThis, "root", ZigString.Slice)) |slice| {
break :brk slice;
}

Expand Down Expand Up @@ -358,7 +358,7 @@ pub const JSBundler = struct {
try this.rootdir.appendSliceExact(rootdir);
}

if (try config.getArray(globalThis, "external")) |externals| {
if (try config.getOwnArray(globalThis, "external")) |externals| {
var iter = externals.arrayIterator(globalThis);
while (iter.next()) |entry_point| {
var slice = entry_point.toSliceOrNull(globalThis) orelse {
Expand All @@ -370,21 +370,21 @@ pub const JSBundler = struct {
}
}

// if (try config.getOptional(globalThis, "dir", ZigString.Slice)) |slice| {
// if (try config.getOwnOptional(globalThis, "dir", ZigString.Slice)) |slice| {
// defer slice.deinit();
// this.appendSliceExact(slice.slice()) catch unreachable;
// } else {
// this.appendSliceExact(globalThis.bunVM().bundler.fs.top_level_dir) catch unreachable;
// }

if (try config.getOptional(globalThis, "publicPath", ZigString.Slice)) |slice| {
if (try config.getOwnOptional(globalThis, "publicPath", ZigString.Slice)) |slice| {
defer slice.deinit();
try this.public_path.appendSliceExact(slice.slice());
}

if (config.getTruthy(globalThis, "naming")) |naming| {
if (config.getOwnTruthy(globalThis, "naming")) |naming| {
if (naming.isString()) {
if (try config.getOptional(globalThis, "naming", ZigString.Slice)) |slice| {
if (try config.getOwnOptional(globalThis, "naming", ZigString.Slice)) |slice| {
defer slice.deinit();
if (!strings.hasPrefixComptime(slice.slice(), "./")) {
try this.names.owned_entry_point.appendSliceExact("./");
Expand All @@ -393,7 +393,7 @@ pub const JSBundler = struct {
this.names.entry_point.data = this.names.owned_entry_point.list.items;
}
} else if (naming.isObject()) {
if (try naming.getOptional(globalThis, "entry", ZigString.Slice)) |slice| {
if (try naming.getOwnOptional(globalThis, "entry", ZigString.Slice)) |slice| {
defer slice.deinit();
if (!strings.hasPrefixComptime(slice.slice(), "./")) {
try this.names.owned_entry_point.appendSliceExact("./");
Expand All @@ -402,7 +402,7 @@ pub const JSBundler = struct {
this.names.entry_point.data = this.names.owned_entry_point.list.items;
}

if (try naming.getOptional(globalThis, "chunk", ZigString.Slice)) |slice| {
if (try naming.getOwnOptional(globalThis, "chunk", ZigString.Slice)) |slice| {
defer slice.deinit();
if (!strings.hasPrefixComptime(slice.slice(), "./")) {
try this.names.owned_chunk.appendSliceExact("./");
Expand All @@ -411,7 +411,7 @@ pub const JSBundler = struct {
this.names.chunk.data = this.names.owned_chunk.list.items;
}

if (try naming.getOptional(globalThis, "asset", ZigString.Slice)) |slice| {
if (try naming.getOwnOptional(globalThis, "asset", ZigString.Slice)) |slice| {
defer slice.deinit();
if (!strings.hasPrefixComptime(slice.slice(), "./")) {
try this.names.owned_asset.appendSliceExact("./");
Expand All @@ -425,7 +425,7 @@ pub const JSBundler = struct {
}
}

if (try config.getObject(globalThis, "define")) |define| {
if (try config.getOwnObject(globalThis, "define")) |define| {
if (!define.isObject()) {
globalThis.throwInvalidArguments("define must be an object", .{});
return error.JSError;
Expand Down Expand Up @@ -463,7 +463,7 @@ pub const JSBundler = struct {
}
}

if (try config.getObject(globalThis, "loader")) |loaders| {
if (try config.getOwnObject(globalThis, "loader")) |loaders| {
var loader_iter = JSC.JSPropertyIterator(.{
.skip_empty_name = true,
.include_value = true,
Expand Down
Loading

0 comments on commit 5722ae8

Please sign in to comment.