Skip to content

Commit 0853372

Browse files
committed
Remove Session serialize/deserialize methods to fix RCE vulnerability
The Session.deserialize method used Oj.load without safe mode, which allows instantiation of arbitrary Ruby objects. If an attacker could control session storage (e.g., compromise a Redis instance or database), they could inject malicious serialized data to achieve remote code execution. These methods were vestigial code from when the library handled session storage (deprecated in v12.3.0). After that deprecation, apps became responsible for their own session persistence, rendering serialize/deserialize unnecessary for their original purpose. Investigation confirmed no external usage - the shopify_app gem stores individual session attributes in database columns and reconstructs sessions using Session.new(). The only internal usage was copy_attributes_from, which called serialize just to enumerate attribute names via JSON.parse(other.serialize).keys before copying instance variables. This has been refactored to directly copy each attribute, eliminating the dependency on serialize. Breaking change: Session#serialize and Session.deserialize removed. Migration: Apps should use Session.new() to reconstruct sessions from stored attributes (the pattern already used by shopify_app). Complete removal eliminates the RCE vector entirely while maintaining all functionality.
1 parent 8522bbd commit 0853372

File tree

2 files changed

+10
-15
lines changed

2 files changed

+10
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Note: For changes to the API, see https://shopify.dev/changelog?filter=api
66
### 15.0.0
77

88
- ⚠️ [Breaking] Removed deprecated `ShopifyAPI::Webhooks::Handler` interface. Apps must migrate to `ShopifyAPI::Webhooks::WebhookHandler` which provides `webhook_id` and `api_version` in addition to `topic`, `shop`, and `body`. See [BREAKING_CHANGES_FOR_V15.md](BREAKING_CHANGES_FOR_V15.md) for migration guide.
9+
- ⚠️ [Breaking] Removed `Session#serialize` and `Session.deserialize` methods due to security concerns (RCE vulnerability via `Oj.load`). These methods were not used internally by the library. If your application relies on session serialization, use `Session.new()` to reconstruct sessions from stored attributes instead.
910
- Add support for 2025-10 API version
1011
- Updated `LATEST_SUPPORTED_ADMIN_VERSION` to `2025-10`
1112
- [#1411](https://github.com/Shopify/shopify-api-ruby/pull/1411) Remove `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants to prevent semver violations. Developers must now explicitly specify API versions. See the [migration guide](BREAKING_CHANGES_FOR_V15.md#removal-of-latest_supported_admin_version-and-release_candidate_admin_version-constants) for details.

lib/shopify_api/auth/session.rb

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -118,28 +118,22 @@ def from(shop:, access_token_response:)
118118
)
119119
end
120120

121-
sig { params(str: String).returns(Session) }
122-
def deserialize(str)
123-
Oj.load(str)
124-
end
125121
end
126122

127123
sig { params(other: Session).returns(Session) }
128124
def copy_attributes_from(other)
129-
JSON.parse(other.serialize).keys.each do |key|
130-
next if key.include?("^")
131-
132-
variable_name = "@#{key}"
133-
instance_variable_set(variable_name, other.instance_variable_get(variable_name))
134-
end
125+
@shop = other.shop
126+
@state = other.state
127+
@access_token = other.access_token
128+
@scope = other.scope
129+
@associated_user_scope = other.associated_user_scope
130+
@expires = other.expires
131+
@associated_user = other.associated_user
132+
@is_online = other.online?
133+
@shopify_session_id = other.shopify_session_id
135134
self
136135
end
137136

138-
sig { returns(String) }
139-
def serialize
140-
Oj.dump(self)
141-
end
142-
143137
alias_method :eql?, :==
144138
sig { params(other: T.nilable(Session)).returns(T::Boolean) }
145139
def ==(other)

0 commit comments

Comments
 (0)