VYPR
Medium severityOSV Advisory· Published Jun 9, 2025· Updated Apr 15, 2026

CVE-2025-49130

CVE-2025-49130

Description

Laravel Translation Manager is a package to manage Laravel translation files. Prior to version 0.6.8, the application is vulnerable to Cross-Site Scripting (XSS) attacks due to incorrect input validation and sanitization of user-input data. An attacker can inject arbitrary HTML code, including JavaScript scripts, into the page processed by the user's browser, allowing them to steal sensitive data, hijack user sessions, or conduct other malicious activities. Only authenticated users with access to the translation manager are impacted. The issue is fixed in version 0.6.8.

AI Insight

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

Laravel Translation Manager prior to 0.6.8 is vulnerable to stored XSS via unsanitized group/locale names, allowing authenticated attackers to execute arbitrary JavaScript.

Vulnerability

Overview Laravel Translation Manager, a package for managing Laravel translation files, is vulnerable to Cross-Site Scripting (XSS) in versions prior to 0.6.8. The root cause is insufficient input validation and sanitization of user-supplied data, specifically group and locale names, which are rendered in the web interface without proper escaping [1]. The commit that fixes the issue replaces raw echo statements with Laravel's e() helper, which HTML-encodes output [1].

Exploitation

Prerequisites An attacker must be an authenticated user with access to the translation manager's web interface [2]. The package provides a web-based editor for translation keys, and the vulnerable fields (group and locale) can be manipulated to inject arbitrary HTML or JavaScript [3]. No other special privileges or network position are required beyond authentication.

Impact

Successful exploitation allows the attacker to execute arbitrary JavaScript in the context of the victim's browser session. This can lead to theft of sensitive data, session hijacking, or other malicious actions performed on behalf of the authenticated user [4].

Mitigation

The vulnerability is fixed in version 0.6.8 of the package [1]. Users are advised to upgrade immediately. No workarounds are documented; the fix involves proper output escaping in the view templates.

AI Insight generated on May 20, 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
barryvdh/laravel-translation-managerPackagist
< 0.6.80.6.8

Affected products

2

Patches

2
527446ed419f

Fix group locale sanitization (#475)

2 files changed · +74 57
  • resources/views/index.php+60 54 modified
    @@ -1,3 +1,14 @@
    +<?php
    +/** @see \Barryvdh\TranslationManager\Controller::getIndex() */
    +/** @var array $translations */
    +/** @var array|string[] $groups */
    +/** @var array|string[] $locales */
    +/** @var string $group */
    +/** @var int $numTranslations */
    +/** @var int $numChanged */
    +/** @var string $editUrl */
    +/** @var bool $deleteEnabled */
    +?>
     <!DOCTYPE html>
     <html>
     <head>
    @@ -123,56 +134,51 @@
             <p>Done searching for translations, found <strong class="counter">N</strong> items!</p>
         </div>
         <div class="alert alert-success success-publish" style="display:none;">
    -        <p>Done publishing the translations for group '<?php echo $group ?>'!</p>
    +        <p>Done publishing the translations for group '<?php echo e($group) ?>'!</p>
         </div>
         <div class="alert alert-success success-publish-all" style="display:none;">
             <p>Done publishing the translations for all group!</p>
         </div>
    -    <?php if(Session::has('successPublish')) : ?>
    -        <div class="alert alert-info">
    -            <?php echo Session::get('successPublish'); ?>
    -        </div>
    -    <?php endif; ?>
         <p>
             <?php if(!isset($group)) : ?>
    -        <form class="form-import" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postImport') ?>" data-remote="true" role="form">
    -            <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    -            <div class="form-group">
    -                <div class="row">
    -                    <div class="col-sm-3">
    -                        <select name="replace" class="form-control">
    -                            <option value="0">Append new translations</option>
    -                            <option value="1">Replace existing translations</option>
    -                        </select>
    -                    </div>
    -                    <div class="col-sm-2">
    +    <form class="form-import" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postImport') ?>" data-remote="true" role="form">
    +        <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    +        <div class="form-group">
    +            <div class="row">
    +                <div class="col-sm-3">
    +                    <select name="replace" class="form-control">
    +                        <option value="0">Append new translations</option>
    +                        <option value="1">Replace existing translations</option>
    +                    </select>
    +                </div>
    +                <div class="col-sm-2">
                         <button type="submit" class="btn btn-success btn-block"  data-disable-with="Loading..">Import groups</button>
    -                    </div>
                     </div>
                 </div>
    +        </div>
    +    </form>
    +    <form class="form-find" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postFind') ?>" data-remote="true" role="form" data-confirm="Are you sure you want to scan you app folder? All found translation keys will be added to the database.">
    +        <div class="form-group">
    +            <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    +            <button type="submit" class="btn btn-info" data-disable-with="Searching.." >Find translations in files</button>
    +        </div>
    +    </form>
    +    <?php endif; ?>
    +    <?php if(isset($group)) : ?>
    +        <form class="form-inline form-publish" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postPublish', $group) ?>" data-remote="true" role="form" data-confirm="Are you sure you want to publish the translations group '<?php echo e($group) ?>? This will overwrite existing language files.">
    +            <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    +            <button type="submit" class="btn btn-info" data-disable-with="Publishing.." >Publish translations</button>
    +            <a href="<?= action('\Barryvdh\TranslationManager\Controller@getIndex') ?>" class="btn btn-default">Back</a>
             </form>
    -        <form class="form-find" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postFind') ?>" data-remote="true" role="form" data-confirm="Are you sure you want to scan you app folder? All found translation keys will be added to the database.">
    -            <div class="form-group">
    -                <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    -                <button type="submit" class="btn btn-info" data-disable-with="Searching.." >Find translations in files</button>
    -            </div>
    -        </form>
    -        <?php endif; ?>
    -        <?php if(isset($group)) : ?>
    -            <form class="form-inline form-publish" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postPublish', $group) ?>" data-remote="true" role="form" data-confirm="Are you sure you want to publish the translations group '<?php echo $group ?>? This will overwrite existing language files.">
    -                <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    -                <button type="submit" class="btn btn-info" data-disable-with="Publishing.." >Publish translations</button>
    -                <a href="<?= action('\Barryvdh\TranslationManager\Controller@getIndex') ?>" class="btn btn-default">Back</a>
    -            </form>
    -        <?php endif; ?>
    +    <?php endif; ?>
         </p>
         <form role="form" method="POST" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postAddGroup') ?>">
             <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
             <div class="form-group">
                 <p>Choose a group to display the group translations. If no groups are visisble, make sure you have run the migrations and imported the translations.</p>
                 <select name="group" id="group" class="form-control group-select">
                     <?php foreach($groups as $key => $value): ?>
    -                    <option value="<?php echo $key ?>"<?php echo $key == $group ? ' selected':'' ?>><?php echo $value ?></option>
    +                    <option value="<?php echo e($key) ?>"<?php echo $key == $group ? ' selected':'' ?>><?php echo e($value) ?></option>
                     <?php endforeach; ?>
                 </select>
             </div>
    @@ -208,7 +214,7 @@
                             <label for="base-locale">Base Locale for Auto Translations</label>
                             <select name="base-locale" id="base-locale" class="form-control">
                                 <?php foreach ($locales as $locale): ?>
    -                                <option value="<?= $locale ?>"><?= $locale ?></option>
    +                                <option value="<?= e($locale) ?>"><?= e($locale) ?></option>
                                 <?php endforeach; ?>
                             </select>
                         </div>
    @@ -230,13 +236,13 @@
                 </div>
             </form>
             <hr>
    -    <h4>Total: <?= $numTranslations ?>, changed: <?= $numChanged ?></h4>
    +        <h4>Total: <?= $numTranslations ?>, changed: <?= $numChanged ?></h4>
             <table class="table">
                 <thead style="position: sticky; top: 0; background: #fff;">
                 <tr>
                     <th width="15%">Key</th>
                     <?php foreach ($locales as $locale): ?>
    -                    <th><?= $locale ?></th>
    +                    <th><?= e($locale) ?></th>
                     <?php endforeach; ?>
                     <?php if ($deleteEnabled): ?>
                         <th>&nbsp;</th>
    @@ -246,26 +252,26 @@
                 <tbody>
     
                 <?php foreach ($translations as $key => $translation): ?>
    -                <tr id="<?php echo htmlentities($key, ENT_QUOTES, 'UTF-8', false) ?>">
    -                    <td><?php echo htmlentities($key, ENT_QUOTES, 'UTF-8', false) ?></td>
    +                <tr id="<?php echo e($key) ?>">
    +                    <td><?php echo e($key) ?></td>
                         <?php foreach ($locales as $locale): ?>
                             <?php $t = isset($translation[$locale]) ? $translation[$locale] : null ?>
     
                             <td>
                                 <a href="#edit"
    -                               class="editable status-<?php echo $t ? $t->status : 0 ?> locale-<?php echo $locale ?>"
    -                               data-locale="<?php echo $locale ?>" data-name="<?php echo $locale . "|" . htmlentities($key, ENT_QUOTES, 'UTF-8', false) ?>"
    -                               id="username" data-type="textarea" data-pk="<?php echo $t ? $t->id : 0 ?>"
    +                               class="editable status-<?php echo $t ? (int) $t->status : 0 ?> locale-<?php echo e($locale) ?>"
    +                               data-locale="<?php echo e($locale) ?>" data-name="<?php echo e($locale) . "|" . e($key) ?>"
    +                               id="username" data-type="textarea" data-pk="<?php echo $t ? (int) $t->id : 0 ?>"
                                    data-url="<?php echo $editUrl ?>"
    -                               data-title="Enter translation"><?php echo $t ? htmlentities($t->value, ENT_QUOTES, 'UTF-8', false) : '' ?></a>
    +                               data-title="Enter translation"><?php echo $t ? e($t->value, false) : '' ?></a>
                             </td>
                         <?php endforeach; ?>
                         <?php if ($deleteEnabled): ?>
                             <td>
                                 <a href="<?php echo action('\Barryvdh\TranslationManager\Controller@postDelete', [$group, $key]) ?>"
                                    class="delete-key"
    -                               data-confirm="Are you sure you want to delete the translations for '<?php echo htmlentities($key, ENT_QUOTES, 'UTF-8', false) ?>?"><span
    -                                        class="glyphicon glyphicon-trash"></span></a>
    +                               data-confirm="Are you sure you want to delete the translations for '<?php echo e($key) ?>?"><span
    +                                    class="glyphicon glyphicon-trash"></span></a>
                             </td>
                         <?php endif; ?>
                     </tr>
    @@ -281,17 +287,17 @@ class="glyphicon glyphicon-trash"></span></a>
                 <form  class="form-remove-locale" method="POST" role="form" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postRemoveLocale') ?>" data-confirm="Are you sure to remove this locale and all of data?">
                     <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
                     <ul class="list-locales">
    -                <?php foreach($locales as $locale): ?>
    -                    <li>
    -                        <div class="form-group">
    -                            <button type="submit" name="remove-locale[<?php echo $locale ?>]" class="btn btn-danger btn-xs" data-disable-with="...">
    -                                &times;
    -                            </button>
    -                            <?php echo $locale ?>
    +                    <?php foreach($locales as $locale): ?>
    +                        <li>
    +                            <div class="form-group">
    +                                <button type="submit" name="remove-locale[<?php echo e($locale) ?>]" class="btn btn-danger btn-xs" data-disable-with="...">
    +                                    &times;
    +                                </button>
    +                                <?php echo e($locale) ?>
     
    -                        </div>
    -                    </li>
    -                <?php endforeach; ?>
    +                            </div>
    +                        </li>
    +                    <?php endforeach; ?>
                     </ul>
                 </form>
                 <form class="form-add-locale" method="POST" role="form" action="<?php echo action('\Barryvdh\TranslationManager\Controller@postAddLocale') ?>">
    
  • src/Controller.php+14 3 modified
    @@ -48,7 +48,7 @@ public function getIndex($group = null)
                 ->with('numTranslations', $numTranslations)
                 ->with('numChanged', $numChanged)
                 ->with('editUrl', $group ? action('\Barryvdh\TranslationManager\Controller@postEdit', [$group]) : null)
    -            ->with('deleteEnabled', $this->manager->getConfig('delete_enabled'));
    +            ->with('deleteEnabled', (bool) $this->manager->getConfig('delete_enabled'));
         }
     
         public function getView($group = null)
    @@ -141,7 +141,7 @@ public function postPublish($group = null)
     
         public function postAddGroup(Request $request)
         {
    -        $group = str_replace(".", '', $request->input('new-group'));
    +        $group = $this->sanitizeFilename($request->input('new-group'));
             if ($group)
             {
                 return redirect()->action('\Barryvdh\TranslationManager\Controller@getView',$group);
    @@ -155,7 +155,7 @@ public function postAddGroup(Request $request)
         public function postAddLocale(Request $request)
         {
             $locales = $this->manager->getLocales();
    -        $newLocale = str_replace([], '-', trim($request->input('new-locale')));
    +        $newLocale = $this->sanitizeFilename($request->input('new-locale'));
             if (!$newLocale || in_array($newLocale, $locales)) {
                 return redirect()->back();
             }
    @@ -200,4 +200,15 @@ public function postTranslateMissing(Request $request){
             }
             return redirect()->back();
         }
    +
    +    protected function sanitizeFilename($input)
    +    {
    +        $input = Str::ascii(trim($input));
    +        return str_replace(
    +            ['<', '>', '%', '/', '\\', '.', ' ', '"', "'", '#', '?'],
    +            '',
    +            $input
    +        );
    +
    +    }
     }
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.