Skip to content

fix(windows): local privilege escalation via binary tampering on unprivileged installs - #16058

Merged
ycombinator merged 9 commits into
elastic:mainfrom
ycombinator:fix/lpe-windows-unprivileged-binary-tampering
Aug 11, 2026
Merged

ycombinator merged 9 commits into
elastic:mainfrom
ycombinator:fix/lpe-windows-unprivileged-binary-tampering

Conversation

@ycombinator

@ycombinator ycombinator commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes a local privilege escalation (LPE) vulnerability on Windows when Elastic Agent is installed with --unprivileged. Two changes:

  1. Removes group write from the default install permission mask (0770 → 0750). The group r-x (read+execute) is sufficient — group members do not need to write to the install directory.

  2. Implements HasStrictExecPerms on Windows, which was a no-op stub (return nil). The implementation reads each file's DACL via GetNamedSecurityInfo and rejects execution if any non-privileged SID (not SYSTEM, not Administrators, not the file owner) holds write-capable access bits (GENERIC_WRITE, GENERIC_ALL, FILE_WRITE_DATA, FILE_APPEND_DATA, FILE_WRITE_EA, FILE_WRITE_ATTRIBUTES, DELETE, WRITE_DAC, WRITE_OWNER).

Also fixes an incidental bug where SystemSID was set to S-1-5-32-544 (the Administrators group SID) rather than S-1-5-18 (the SYSTEM account SID).

Why is it important?

On Windows unprivileged installs, the elastic-agent group was granted Modify (write) access to component binaries (e.g. agentbeat.exe) because the default mask 0770 translates the group-write bit to Windows Modify permissions. Any local user in the elastic-agent group could replace a component binary. After a restart, the agent service would execute the tampered binary as elastic-agent-user, which holds SeImpersonatePrivilege, enabling escalation to NT AUTHORITY\SYSTEM via standard potato-class exploits.

Checklist

  • I have read and understood the pull request guidelines of this project.
  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have made corresponding change to the default configuration files
  • I have added tests that prove my fix is effective or that my feature works
  • I have added an entry in ./changelog/fragments using the changelog tool
  • I have added an integration test or an E2E test

Disruptive User Impact

The permission mask change (0770 → 0750) removes write access for members of the elastic-agent group to files in the install directory. Group members were only ever intended to interact with the agent via its socket — not to write files. There is no expected disruption to legitimate use cases.

How to test this PR locally

Requires a Windows (amd64) machine.

1. Build for Windows (amd64)

PLATFORMS=windows/amd64 mage package
# Produces: build/distributions/elastic-agent-<version>-windows-x86_64.zip

2. Install in unprivileged mode on the Windows machine

Open PowerShell as Administrator, then:

# Extract the zip
Expand-Archive -Path "elastic-agent-<version>-windows-x86_64.zip" -DestinationPath C:\Temp\ea
Set-Location "C:\Temp\ea\elastic-agent-<version>-windows-x86_64"

# Install in unprivileged mode (creates elastic-agent-user account and elastic-agent group)
.\elastic-agent.exe install --unprivileged --non-interactive

3. Verify the permission fix (Commit 1)

# Group should show (RX) — read+execute only — not (M) for Modify
icacls "C:\Program Files\Elastic\Agent\data\elastic-agent-*\components\agentbeat.exe"

4. Verify HasStrictExecPerms (Commit 3)

Add a non-privileged user to the elastic-agent group (to simulate the attack surface), grant Everyone write on a component binary, then confirm the agent refuses to start that component:

# Grant Everyone write access to agentbeat.exe
$target = (Get-Item "C:\Program Files\Elastic\Agent\data\elastic-agent-*\components\agentbeat.exe").FullName
icacls $target /grant "Everyone:(W)"

# Restart the agent service and check logs for the rejection
Restart-Service elastic-agent
# In C:\Program Files\Elastic\Agent\data\elastic-agent-*\logs\elastic-agent-*.ndjson,
# look for: "non-privileged SID ... has write access"

Related issues

@ycombinator
ycombinator requested a review from a team as a code owner August 6, 2026 14:54
@ycombinator
ycombinator requested a review from macdewee August 6, 2026 14:54
@ycombinator ycombinator added the Team:Elastic-Agent-Control-Plane Label for the Agent Control Plane team label Aug 6, 2026
@ycombinator
ycombinator requested a review from swiatekm August 6, 2026 14:54
@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

Pinging @elastic/elastic-agent-control-plane (Team:Elastic-Agent-Control-Plane)

@mergify

mergify Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

This pull request does not have a backport label. Could you fix it @ycombinator? 🙏
To fixup this pull request, you need to add the backport labels for the needed
branches, such as:

  • backport-./d./d is the label that automatically backports to the 8./d branch. /d is the digit
  • backport-active-all is the label that automatically backports to all active branches.
  • backport-active-8 is the label that automatically backports to all active minor branches for the 8 major.
  • backport-active-9 is the label that automatically backports to all active minor branches for the 9 major.

@ycombinator ycombinator added the backport-active-all Automated backport with mergify to all the active branches label Aug 6, 2026
@ycombinator
ycombinator requested review from leehinman and removed request for macdewee and swiatekm August 6, 2026 16:57

@leehinman leehinman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM.

Claude flagged needing runtime.KeepAlive(sd), needs double checking.

Comment thread pkg/utils/perm_windows.go
@ycombinator
ycombinator requested a review from leehinman August 6, 2026 18:55
leehinman
leehinman previously approved these changes Aug 6, 2026
@ycombinator
ycombinator force-pushed the fix/lpe-windows-unprivileged-binary-tampering branch from 5cca22a to aae1cba Compare August 7, 2026 13:37
blakerouse
blakerouse previously approved these changes Aug 7, 2026

@blakerouse blakerouse left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@ycombinator
ycombinator force-pushed the fix/lpe-windows-unprivileged-binary-tampering branch from aae1cba to 15fb6c0 Compare August 7, 2026 14:54
@ycombinator
ycombinator enabled auto-merge (squash) August 7, 2026 14:56
@ycombinator
ycombinator dismissed stale reviews from leehinman and blakerouse via 95051f6 August 7, 2026 19:40
leehinman
leehinman previously approved these changes Aug 7, 2026
blakerouse
blakerouse previously approved these changes Aug 7, 2026
@ycombinator
ycombinator force-pushed the fix/lpe-windows-unprivileged-binary-tampering branch from 95051f6 to 8eb2235 Compare August 7, 2026 23:24
@ycombinator
ycombinator dismissed stale reviews from blakerouse and leehinman via 1021e6b August 7, 2026 23:25
@ycombinator
ycombinator force-pushed the fix/lpe-windows-unprivileged-binary-tampering branch from 1021e6b to dc93771 Compare August 10, 2026 15:05
@infra-vault-gh-plugin-prod

infra-vault-gh-plugin-prod Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

💔 Build Failed

Failed CI Steps

History

cc @ycombinator

ycombinator and others added 9 commits August 10, 2026 10:17
The default mask 0770 translated to Modify (write) access for the
elastic-agent group on Windows ACLs. Members of that group could
replace component binaries and have them executed by the service
account after a restart. Changed to 0750 so the group retains
read+execute but loses write.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SystemSID was set to S-1-5-32-544 (the Administrators group), the same
as AdministratorSID. The SYSTEM account SID is S-1-5-18. This meant the
SYSTEM account was never explicitly granted access in FixPermissions ACLs,
and the HasStrictExecPerms implementation about to be added would not have
correctly allowed SYSTEM write access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Windows implementation was a no-op stub that always returned nil,
allowing the agent to execute component binaries whose ACLs had been
tampered with. This meant a member of the elastic-agent group could
replace agentbeat.exe and have it run as elastic-agent-user, which
holds SeImpersonatePrivilege and can be escalated to SYSTEM.

The implementation reads the file's DACL via GetNamedSecurityInfo and
checks every ACCESS_ALLOWED_ACE. SYSTEM, Administrators, and the file
owner may hold any access; any other SID with write-capable bits
(GENERIC_WRITE, GENERIC_ALL, FILE_WRITE_DATA, FILE_APPEND_DATA,
FILE_WRITE_EA, FILE_WRITE_ATTRIBUTES, DELETE, WRITE_DAC, WRITE_OWNER)
is rejected with an error, preventing execution.

HasStrictExecPermsAndOwnership delegates to HasStrictExecPerms; the
uid parameter has no Windows equivalent and is ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The SystemSID fix (S-1-5-32-544 → S-1-5-18) means SYSTEM and
Administrators are now separate entries in the ACL. Update the
unprivileged install check to assert SYSTEM's presence and allow
5 unique SIDs instead of 4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defensive guard: keeps the SECURITY_DESCRIPTOR alive through the ACE
loop so that derived interior pointers (dacl, ace, sid) remain valid
even if a future x/sys version backs the SD with Windows-heap memory
subject to a GC finalizer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…istinct ACE

The SystemSID fix (S-1-5-32-544 → S-1-5-18) means SYSTEM now gets its
own ACE separate from Administrators in both privileged and unprivileged
installs. Update the privileged branch to expect 3 SIDs (Administrators,
SYSTEM, Interactive) and assert SYSTEM is present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ility

Old agents (pre SystemSID fix) collapsed SYSTEM and Administrators into
a single ACE (S-1-5-32-544). Upgrade tests install the old agent first,
so the pre-upgrade DACL check must not hard-require a distinct SYSTEM ACE.
Raise the max SID counts (unprivileged: 5, privileged: 3) to allow SYSTEM
when present, but drop the hard assertion so old installs still pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ycombinator
ycombinator force-pushed the fix/lpe-windows-unprivileged-binary-tampering branch from dc93771 to 1a77a57 Compare August 10, 2026 17:17
@ycombinator
ycombinator merged commit eb324b0 into elastic:main Aug 11, 2026
23 checks passed
@ycombinator
ycombinator deleted the fix/lpe-windows-unprivileged-binary-tampering branch August 11, 2026 17:01
@ycombinator

Copy link
Copy Markdown
Contributor Author

@Mergifyio backport 9.5 9.4 8.19

@mergify

mergify Bot commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

backport 9.5 9.4 8.19

✅ Backports have been created

Details

Cherry-pick of eb324b0 has failed:

On branch mergify/bp/8.19/pr-16058
Your branch is up to date with 'origin/8.19'.

You are currently cherry-picking commit eb324b0b2.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	new file:   changelog/fragments/1786027979-fix-local-privilege-escalation-via-binary-tampering-on-windows-unprivileged-installs.yaml
	modified:   internal/pkg/agent/perms/opts.go
	modified:   internal/pkg/agent/perms/unix_test.go
	new file:   pkg/utils/perm_windows_test.go
	modified:   testing/installtest/checks_windows.go

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   pkg/utils/perm_windows.go

To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally

ycombinator added a commit that referenced this pull request Aug 11, 2026
…ivileged installs (#16058) (#16154)

* fix(windows): remove group write from default install permissions

The default mask 0770 translated to Modify (write) access for the
elastic-agent group on Windows ACLs. Members of that group could
replace component binaries and have them executed by the service
account after a restart. Changed to 0750 so the group retains
read+execute but loses write.



* fix(windows): correct SystemSID constant value

SystemSID was set to S-1-5-32-544 (the Administrators group), the same
as AdministratorSID. The SYSTEM account SID is S-1-5-18. This meant the
SYSTEM account was never explicitly granted access in FixPermissions ACLs,
and the HasStrictExecPerms implementation about to be added would not have
correctly allowed SYSTEM write access.



* fix(windows): implement HasStrictExecPerms to block tampered binaries

The Windows implementation was a no-op stub that always returned nil,
allowing the agent to execute component binaries whose ACLs had been
tampered with. This meant a member of the elastic-agent group could
replace agentbeat.exe and have it run as elastic-agent-user, which
holds SeImpersonatePrivilege and can be escalated to SYSTEM.

The implementation reads the file's DACL via GetNamedSecurityInfo and
checks every ACCESS_ALLOWED_ACE. SYSTEM, Administrators, and the file
owner may hold any access; any other SID with write-capable bits
(GENERIC_WRITE, GENERIC_ALL, FILE_WRITE_DATA, FILE_APPEND_DATA,
FILE_WRITE_EA, FILE_WRITE_ATTRIBUTES, DELETE, WRITE_DAC, WRITE_OWNER)
is rejected with an error, preventing execution.

HasStrictExecPermsAndOwnership delegates to HasStrictExecPerms; the
uid parameter has no Windows equivalent and is ignored.



* chore: add changelog fragment for Windows LPE security fix



* fix(windows): fix sid.String() call — returns one value not two



* fix(test): update Windows DACL check to expect SYSTEM as distinct ACE

The SystemSID fix (S-1-5-32-544 → S-1-5-18) means SYSTEM and
Administrators are now separate entries in the ACL. Update the
unprivileged install check to assert SYSTEM's presence and allow
5 unique SIDs instead of 4.



* fix(windows): add runtime.KeepAlive(sd) in HasStrictExecPerms

Defensive guard: keeps the SECURITY_DESCRIPTOR alive through the ACE
loop so that derived interior pointers (dacl, ace, sid) remain valid
even if a future x/sys version backs the SD with Windows-heap memory
subject to a GC finalizer.



---------


(cherry picked from commit eb324b0)

Co-authored-by: Shaunak Kashyap <ycombinator@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ycombinator added a commit that referenced this pull request Aug 12, 2026
…ivileged installs (#16058)

* fix(windows): remove group write from default install permissions

The default mask 0770 translated to Modify (write) access for the
elastic-agent group on Windows ACLs. Members of that group could
replace component binaries and have them executed by the service
account after a restart. Changed to 0750 so the group retains
read+execute but loses write.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): correct SystemSID constant value

SystemSID was set to S-1-5-32-544 (the Administrators group), the same
as AdministratorSID. The SYSTEM account SID is S-1-5-18. This meant the
SYSTEM account was never explicitly granted access in FixPermissions ACLs,
and the HasStrictExecPerms implementation about to be added would not have
correctly allowed SYSTEM write access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): implement HasStrictExecPerms to block tampered binaries

The Windows implementation was a no-op stub that always returned nil,
allowing the agent to execute component binaries whose ACLs had been
tampered with. This meant a member of the elastic-agent group could
replace agentbeat.exe and have it run as elastic-agent-user, which
holds SeImpersonatePrivilege and can be escalated to SYSTEM.

The implementation reads the file's DACL via GetNamedSecurityInfo and
checks every ACCESS_ALLOWED_ACE. SYSTEM, Administrators, and the file
owner may hold any access; any other SID with write-capable bits
(GENERIC_WRITE, GENERIC_ALL, FILE_WRITE_DATA, FILE_APPEND_DATA,
FILE_WRITE_EA, FILE_WRITE_ATTRIBUTES, DELETE, WRITE_DAC, WRITE_OWNER)
is rejected with an error, preventing execution.

HasStrictExecPermsAndOwnership delegates to HasStrictExecPerms; the
uid parameter has no Windows equivalent and is ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add changelog fragment for Windows LPE security fix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): fix sid.String() call — returns one value not two

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): update Windows DACL check to expect SYSTEM as distinct ACE

The SystemSID fix (S-1-5-32-544 → S-1-5-18) means SYSTEM and
Administrators are now separate entries in the ACL. Update the
unprivileged install check to assert SYSTEM's presence and allow
5 unique SIDs instead of 4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): add runtime.KeepAlive(sd) in HasStrictExecPerms

Defensive guard: keeps the SECURITY_DESCRIPTOR alive through the ACE
loop so that derived interior pointers (dacl, ace, sid) remain valid
even if a future x/sys version backs the SD with Windows-heap memory
subject to a GC finalizer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit eb324b0)
ycombinator added a commit that referenced this pull request Aug 12, 2026
…ivileged installs (#16058) (#16153)

* fix(windows): remove group write from default install permissions

The default mask 0770 translated to Modify (write) access for the
elastic-agent group on Windows ACLs. Members of that group could
replace component binaries and have them executed by the service
account after a restart. Changed to 0750 so the group retains
read+execute but loses write.



* fix(windows): correct SystemSID constant value

SystemSID was set to S-1-5-32-544 (the Administrators group), the same
as AdministratorSID. The SYSTEM account SID is S-1-5-18. This meant the
SYSTEM account was never explicitly granted access in FixPermissions ACLs,
and the HasStrictExecPerms implementation about to be added would not have
correctly allowed SYSTEM write access.



* fix(windows): implement HasStrictExecPerms to block tampered binaries

The Windows implementation was a no-op stub that always returned nil,
allowing the agent to execute component binaries whose ACLs had been
tampered with. This meant a member of the elastic-agent group could
replace agentbeat.exe and have it run as elastic-agent-user, which
holds SeImpersonatePrivilege and can be escalated to SYSTEM.

The implementation reads the file's DACL via GetNamedSecurityInfo and
checks every ACCESS_ALLOWED_ACE. SYSTEM, Administrators, and the file
owner may hold any access; any other SID with write-capable bits
(GENERIC_WRITE, GENERIC_ALL, FILE_WRITE_DATA, FILE_APPEND_DATA,
FILE_WRITE_EA, FILE_WRITE_ATTRIBUTES, DELETE, WRITE_DAC, WRITE_OWNER)
is rejected with an error, preventing execution.

HasStrictExecPermsAndOwnership delegates to HasStrictExecPerms; the
uid parameter has no Windows equivalent and is ignored.



* chore: add changelog fragment for Windows LPE security fix



* fix(windows): fix sid.String() call — returns one value not two



* fix(test): update Windows DACL check to expect SYSTEM as distinct ACE

The SystemSID fix (S-1-5-32-544 → S-1-5-18) means SYSTEM and
Administrators are now separate entries in the ACL. Update the
unprivileged install check to assert SYSTEM's presence and allow
5 unique SIDs instead of 4.



* fix(windows): add runtime.KeepAlive(sd) in HasStrictExecPerms

Defensive guard: keeps the SECURITY_DESCRIPTOR alive through the ACE
loop so that derived interior pointers (dacl, ace, sid) remain valid
even if a future x/sys version backs the SD with Windows-heap memory
subject to a GC finalizer.



---------


(cherry picked from commit eb324b0)

Co-authored-by: Shaunak Kashyap <ycombinator@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ycombinator added a commit that referenced this pull request Aug 12, 2026
… binary tampering on unprivileged installs (#16155)

* fix(windows): local privilege escalation via binary tampering on unprivileged installs (#16058)

* fix(windows): remove group write from default install permissions

The default mask 0770 translated to Modify (write) access for the
elastic-agent group on Windows ACLs. Members of that group could
replace component binaries and have them executed by the service
account after a restart. Changed to 0750 so the group retains
read+execute but loses write.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): correct SystemSID constant value

SystemSID was set to S-1-5-32-544 (the Administrators group), the same
as AdministratorSID. The SYSTEM account SID is S-1-5-18. This meant the
SYSTEM account was never explicitly granted access in FixPermissions ACLs,
and the HasStrictExecPerms implementation about to be added would not have
correctly allowed SYSTEM write access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): implement HasStrictExecPerms to block tampered binaries

The Windows implementation was a no-op stub that always returned nil,
allowing the agent to execute component binaries whose ACLs had been
tampered with. This meant a member of the elastic-agent group could
replace agentbeat.exe and have it run as elastic-agent-user, which
holds SeImpersonatePrivilege and can be escalated to SYSTEM.

The implementation reads the file's DACL via GetNamedSecurityInfo and
checks every ACCESS_ALLOWED_ACE. SYSTEM, Administrators, and the file
owner may hold any access; any other SID with write-capable bits
(GENERIC_WRITE, GENERIC_ALL, FILE_WRITE_DATA, FILE_APPEND_DATA,
FILE_WRITE_EA, FILE_WRITE_ATTRIBUTES, DELETE, WRITE_DAC, WRITE_OWNER)
is rejected with an error, preventing execution.

HasStrictExecPermsAndOwnership delegates to HasStrictExecPerms; the
uid parameter has no Windows equivalent and is ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add changelog fragment for Windows LPE security fix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): fix sid.String() call — returns one value not two

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): update Windows DACL check to expect SYSTEM as distinct ACE

The SystemSID fix (S-1-5-32-544 → S-1-5-18) means SYSTEM and
Administrators are now separate entries in the ACL. Update the
unprivileged install check to assert SYSTEM's presence and allow
5 unique SIDs instead of 4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): add runtime.KeepAlive(sd) in HasStrictExecPerms

Defensive guard: keeps the SECURITY_DESCRIPTOR alive through the ACE
loop so that derived interior pointers (dacl, ace, sid) remain valid
even if a future x/sys version backs the SD with Windows-heap memory
subject to a GC finalizer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit eb324b0)

# Conflicts:
#	pkg/utils/perm_windows.go

* fix: resolve 8.19 Windows permissions backport conflict

---------

Co-authored-by: Shaunak Kashyap <ycombinator@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-active-all Automated backport with mergify to all the active branches Team:Elastic-Agent-Control-Plane Label for the Agent Control Plane team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants