Skip to content

Commit

Permalink
fix: prevent injecting side-loaded gdscripts which are not inline
Browse files Browse the repository at this point in the history
  • Loading branch information
derkork committed Nov 19, 2023
1 parent 361898e commit 1e5801d
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2023-11-19
### Breaking change
- Added a scan for any kind of resource that is outside of res://. If resources now contain any reference to another resource that is outside of res:// they will not be loaded. This prevents injecting scripts by putting script files next to the resource.

## [0.0.1] - 2023-10-12
- Initial release.
21 changes: 20 additions & 1 deletion addons/safe_resource_loader/safe_resource_loader.gd
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,26 @@ static func load(path:String, type_hint:String = "", \
if regex.search(file_as_text) != null:
push_warning("Resource '" + path + "' contains inline GDScripts, will not load it.")
return null


# Check all ext resources, and verify that all their paths start with res://
# This is to prevent loading resources from outside the game directory.
#
# Format is:
# [ext_resource type="Script" path="res://safe_resource_loader_example/saved_game.gd" id="1_on72l"]
# there can be arbitrary whitespace between [] or the key/value pairs. the order of the key/value pairs is arbitrary.
# we want to match the path key, and then check that the value starts with res://
# the type doesn't matter, as resources themselves could contain further resources, which in turn could contain
# scripts, so we flat-out refuse to load ANY resource that isn't in res://

var extResourceRegex:RegEx = RegEx.new()
extResourceRegex.compile("\\[\\s*ext_resource\\s*.*?path\\s*=\\s*\"([^\"]*)\".*?\\]")
var matches:Array = extResourceRegex.search_all(file_as_text)
for match in matches:
var resourcePath:String = match.get_string(1)
if not resourcePath.begins_with("res://"):
push_warning("Resource '" + path + "' contains an ext_resource with a path\n outside 'res://' (path is: '" + resourcePath + "'), will not load it.")
return null

# otherwise use the normal resource loader to load it.
return ResourceLoader.load(path, type_hint, cache_mode)

13 changes: 13 additions & 0 deletions safe_resource_loader_example/another_unsafe_resource.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[gd_resource type="Resource" script_class="SRLSavedGame" load_steps=4 format=3 uid="uid://cx4rf0ybe3u7o"]

[ext_resource type="Script" path="res://safe_resource_loader_example/saved_game.gd" id="1_on72l"]

[ ext_resource path="my_script.gd" type="Script" id="4711"]

[sub_resource type="Resource" id="Resource_a4lfc"]
script = ExtResource("4711")

[resource]
script = ExtResource("1_on72l")
health = 200
metadata/hack = SubResource("Resource_a4lfc")
2 changes: 2 additions & 0 deletions safe_resource_loader_example/my_script.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
func _init():
OS.alert("Heya I just executed code via a side-loaded script!")

0 comments on commit 1e5801d

Please sign in to comment.