VYPR
Moderate severityNVD Advisory· Published Aug 19, 2025· Updated Aug 20, 2025

CVE-2025-51488

CVE-2025-51488

Description

A Stored Cross-Site Scripting (XSS) vulnerability exists in MoonShine version < 3.12.4, allowing remote attackers to store and execute arbitrary JavaScript by including a malicious HTML payload in the Name parameter when creating a new Admin.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Stored XSS in MoonShine < 3.12.4 allows attackers to inject arbitrary JavaScript via the Name parameter when creating an Admin.

A Stored Cross-Site Scripting (XSS) vulnerability exists in MoonShine versions prior to 3.12.4. The root cause is insufficient sanitization of the Name parameter during admin user creation, allowing arbitrary HTML to be persisted. [1]

An attacker with admin privileges (PR:H) can craft a payload such as `` and submit it via the Name field. The payload is stored and executed when any user views a page that renders the admin name, with no user interaction required (UI:N). [2]

The stored script executes in the context of the victim's session, potentially leading to unauthorized actions or data theft. The CVSS 3.1 score is 4.9 (Medium) with high confidentiality impact. [1][2]

The issue is fixed in MoonShine 3.12.4, confirmed by the commit that escapes output using WithEscapedValue trait. Users should upgrade immediately. [2][4]

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
moonshine/moonshinePackagist
< 3.12.143.12.14

Affected products

2

Patches

1
f108f4ea5c0d

fix: Security issue

https://github.com/moonshine-software/moonshineDanil ShutskyMay 14, 2025via ghsa
6 files changed · +41 12
  • src/Laravel/src/Fields/Relationships/BelongsTo.php+8 2 modified
    @@ -18,6 +18,7 @@
     use MoonShine\UI\Traits\Fields\HasPlaceholder;
     use MoonShine\UI\Traits\Fields\Searchable;
     use MoonShine\UI\Traits\Fields\WithDefaultValue;
    +use MoonShine\UI\Traits\Fields\WithEscapedValue;
     use Throwable;
     
     /**
    @@ -37,6 +38,7 @@ class BelongsTo extends ModelRelationField implements
         use WithDefaultValue;
         use HasPlaceholder;
         use BelongsToOrManyCreatable;
    +    use WithEscapedValue;
     
         protected string $view = 'moonshine::fields.relationships.belongs-to';
     
    @@ -50,7 +52,9 @@ class BelongsTo extends ModelRelationField implements
         protected function resolvePreview(): string
         {
             if (! $this->getResource()->hasAnyAction(Action::VIEW, Action::UPDATE)) {
    -            return parent::resolvePreview();
    +            return $this->isUnescape()
    +                ? parent::resolvePreview()
    +                : $this->escapeValue((string) parent::resolvePreview());
             }
     
             if (! $this->hasLink() && $this->toValue()) {
    @@ -68,7 +72,9 @@ protected function resolvePreview(): string
                 );
             }
     
    -        return parent::resolvePreview();
    +        return $this->isUnescape()
    +            ? parent::resolvePreview()
    +            : $this->escapeValue((string) parent::resolvePreview());
         }
     
         protected function resolveValue(): mixed
    
  • src/Laravel/src/Fields/Relationships/MorphTo.php+5 1 modified
    @@ -143,11 +143,15 @@ protected function resolvePreview(): string
             $column = $this->getSearchColumn($value::class);
             $type = $item->{$this->getMorphType()};
     
    -        return str($this->types[$type] ?? $type)
    +        $preview = str($this->types[$type] ?? $type)
                 ->append('(')
                 ->append(data_get($value, $column))
                 ->append(')')
                 ->value();
    +
    +        return $this->isUnescape()
    +            ? $preview
    +            : $this->escapeValue($preview);
         }
     
         public function getTypeValue(): string
    
  • src/Support/src/DTOs/Select/Option.php+10 2 modified
    @@ -18,12 +18,20 @@ public function __construct(
     
         public function getLabel(): string
         {
    -        return $this->label;
    +        return htmlspecialchars(
    +            $this->label,
    +            ENT_QUOTES | ENT_SUBSTITUTE,
    +            'UTF-8',
    +        );
         }
     
         public function getValue(): string
         {
    -        return $this->value;
    +        return htmlspecialchars(
    +            $this->value,
    +            ENT_QUOTES | ENT_SUBSTITUTE,
    +            'UTF-8',
    +        );
         }
     
         public function isSelected(): bool
    
  • src/UI/src/Components/Link.php+5 1 modified
    @@ -73,7 +73,11 @@ public function getView(): string
         protected function prepareBeforeRender(): void
         {
             $this->customAttributes([
    -            'href' => value($this->href, $this),
    +            'href' => htmlspecialchars(
    +                value($this->href, $this),
    +                ENT_QUOTES | ENT_SUBSTITUTE,
    +                'UTF-8',
    +            ),
             ]);
         }
     
    
  • src/UI/src/Fields/Url.php+8 5 modified
    @@ -7,7 +7,7 @@
     use Closure;
     use Illuminate\Contracts\Support\Renderable;
     use MoonShine\Support\Enums\TextWrap;
    -use MoonShine\UI\Components\Url as UrlComponent;
    +use MoonShine\UI\Components\Link;
     
     class Url extends Text
     {
    @@ -36,6 +36,7 @@ public function blank(): static
         protected function resolvePreview(): Renderable|string
         {
             $value = $this->toFormattedValue() ?? '';
    +
             $title = $this->isUnescape()
                 ? $value
                 : $this->escapeValue($value);
    @@ -44,12 +45,14 @@ protected function resolvePreview(): Renderable|string
                 return '';
             }
     
    -        return UrlComponent::make(
    +        return Link::make(
                 href: $value,
    -            value: \is_null($this->titleCallback)
    +            label: \is_null($this->titleCallback)
                     ? $title
                     : (string) \call_user_func($this->titleCallback, $title, $this),
    -            blank: $this->blank
    -        )->render();
    +        )->when(
    +            $this->blank,
    +            fn (Link $ctx): Link => $ctx->blank()
    +        )->icon('link')->render();
         }
     }
    
  • src/UI/src/Traits/Fields/WithLink.php+5 1 modified
    @@ -27,7 +27,11 @@ public function hasLink(): bool
     
         public function getLinkValue(mixed $value = null): string
         {
    -        return value($this->linkValue, $value ?? $this->toValue(withDefault: false), $this);
    +        return htmlspecialchars(
    +            value($this->linkValue, $value ?? $this->toValue(withDefault: false), $this),
    +            ENT_QUOTES | ENT_SUBSTITUTE,
    +            'UTF-8',
    +        );
         }
     
         public function getLinkName(mixed $value = null): string
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.