Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
bd9bc17a
Commit
bd9bc17a
authored
Aug 26, 2021
by
Coung Ngo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix GFM autocomplete xss
Changelog: security
parent
905e6500
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
59 additions
and
15 deletions
+59
-15
app/assets/javascripts/gfm_auto_complete.js
app/assets/javascripts/gfm_auto_complete.js
+23
-10
ee/app/assets/javascripts/gfm_auto_complete.js
ee/app/assets/javascripts/gfm_auto_complete.js
+2
-2
spec/frontend/gfm_auto_complete_spec.js
spec/frontend/gfm_auto_complete_spec.js
+34
-3
No files found.
app/assets/javascripts/gfm_auto_complete.js
View file @
bd9bc17a
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
'
~/lib/utils/jquery_at_who
'
;
import
'
~/lib/utils/jquery_at_who
'
;
import
{
escape
,
sortBy
,
template
}
from
'
lodash
'
;
import
{
escape
as
lodashEscape
,
sortBy
,
template
}
from
'
lodash
'
;
import
*
as
Emoji
from
'
~/emoji
'
;
import
*
as
Emoji
from
'
~/emoji
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
s__
,
__
,
sprintf
}
from
'
~/locale
'
;
import
{
s__
,
__
,
sprintf
}
from
'
~/locale
'
;
...
@@ -11,8 +11,21 @@ import { spriteIcon } from './lib/utils/common_utils';
...
@@ -11,8 +11,21 @@ import { spriteIcon } from './lib/utils/common_utils';
import
{
parsePikadayDate
}
from
'
./lib/utils/datetime_utility
'
;
import
{
parsePikadayDate
}
from
'
./lib/utils/datetime_utility
'
;
import
glRegexp
from
'
./lib/utils/regexp
'
;
import
glRegexp
from
'
./lib/utils/regexp
'
;
function
sanitize
(
str
)
{
/**
return
str
.
replace
(
/<
(?:
.|
\n)
*
?
>/gm
,
''
);
* Escapes user input before we pass it to at.js, which
* renders it as HTML in the autocomplete dropdown.
*
* at.js allows you to reference data using `${}` syntax
* (e.g. ${search}) which it replaces with the actual data
* before rendering it in the autocomplete dropdown.
* To prevent user input from executing this `${}` syntax,
* we also need to escape the $ character.
*
* @param string user input
* @return {string} escaped user input
*/
function
escape
(
string
)
{
return
lodashEscape
(
string
).
replace
(
/
\$
/g
,
'
$
'
);
}
}
function
createMemberSearchString
(
member
)
{
function
createMemberSearchString
(
member
)
{
...
@@ -44,8 +57,8 @@ export function membersBeforeSave(members) {
...
@@ -44,8 +57,8 @@ export function membersBeforeSave(members) {
return
{
return
{
username
:
member
.
username
,
username
:
member
.
username
,
avatarTag
:
autoCompleteAvatar
.
length
===
1
?
txtAvatar
:
imgAvatar
,
avatarTag
:
autoCompleteAvatar
.
length
===
1
?
txtAvatar
:
imgAvatar
,
title
:
sanitize
(
title
)
,
title
,
search
:
sanitize
(
createMemberSearchString
(
member
)
),
search
:
createMemberSearchString
(
member
),
icon
:
avatarIcon
,
icon
:
avatarIcon
,
availability
:
member
?.
availability
,
availability
:
member
?.
availability
,
};
};
...
@@ -366,7 +379,7 @@ class GfmAutoComplete {
...
@@ -366,7 +379,7 @@ class GfmAutoComplete {
}
}
return
{
return
{
id
:
i
.
iid
,
id
:
i
.
iid
,
title
:
sanitize
(
i
.
title
)
,
title
:
i
.
title
,
reference
:
i
.
reference
,
reference
:
i
.
reference
,
search
:
`
${
i
.
iid
}
${
i
.
title
}
`
,
search
:
`
${
i
.
iid
}
${
i
.
title
}
`
,
};
};
...
@@ -404,7 +417,7 @@ class GfmAutoComplete {
...
@@ -404,7 +417,7 @@ class GfmAutoComplete {
return
{
return
{
id
:
m
.
iid
,
id
:
m
.
iid
,
title
:
sanitize
(
m
.
title
)
,
title
:
m
.
title
,
search
:
m
.
title
,
search
:
m
.
title
,
expired
,
expired
,
dueDate
,
dueDate
,
...
@@ -456,7 +469,7 @@ class GfmAutoComplete {
...
@@ -456,7 +469,7 @@ class GfmAutoComplete {
}
}
return
{
return
{
id
:
m
.
iid
,
id
:
m
.
iid
,
title
:
sanitize
(
m
.
title
)
,
title
:
m
.
title
,
reference
:
m
.
reference
,
reference
:
m
.
reference
,
search
:
`
${
m
.
iid
}
${
m
.
title
}
`
,
search
:
`
${
m
.
iid
}
${
m
.
title
}
`
,
};
};
...
@@ -492,7 +505,7 @@ class GfmAutoComplete {
...
@@ -492,7 +505,7 @@ class GfmAutoComplete {
beforeSave
(
merges
)
{
beforeSave
(
merges
)
{
if
(
GfmAutoComplete
.
isLoading
(
merges
))
return
merges
;
if
(
GfmAutoComplete
.
isLoading
(
merges
))
return
merges
;
return
$
.
map
(
merges
,
(
m
)
=>
({
return
$
.
map
(
merges
,
(
m
)
=>
({
title
:
sanitize
(
m
.
title
)
,
title
:
m
.
title
,
color
:
m
.
color
,
color
:
m
.
color
,
search
:
m
.
title
,
search
:
m
.
title
,
set
:
m
.
set
,
set
:
m
.
set
,
...
@@ -586,7 +599,7 @@ class GfmAutoComplete {
...
@@ -586,7 +599,7 @@ class GfmAutoComplete {
}
}
return
{
return
{
id
:
m
.
id
,
id
:
m
.
id
,
title
:
sanitize
(
m
.
title
)
,
title
:
m
.
title
,
search
:
`
${
m
.
id
}
${
m
.
title
}
`
,
search
:
`
${
m
.
id
}
${
m
.
title
}
`
,
};
};
});
});
...
...
ee/app/assets/javascripts/gfm_auto_complete.js
View file @
bd9bc17a
...
@@ -48,7 +48,7 @@ class GfmAutoCompleteEE extends GfmAutoComplete {
...
@@ -48,7 +48,7 @@ class GfmAutoCompleteEE extends GfmAutoComplete {
return
{
return
{
id
:
m
.
iid
,
id
:
m
.
iid
,
reference
:
m
.
reference
,
reference
:
m
.
reference
,
title
:
m
.
title
.
replace
(
/<
(?:
.|
\n)
*
?
>/gm
,
''
)
,
title
:
m
.
title
,
search
:
`
${
m
.
iid
}
${
m
.
title
}
`
,
search
:
`
${
m
.
iid
}
${
m
.
title
}
`
,
};
};
});
});
...
@@ -82,7 +82,7 @@ class GfmAutoCompleteEE extends GfmAutoComplete {
...
@@ -82,7 +82,7 @@ class GfmAutoCompleteEE extends GfmAutoComplete {
}
}
return
{
return
{
id
:
m
.
id
,
id
:
m
.
id
,
title
:
m
.
title
.
replace
(
/<
(?:
.|
\n)
*
?
>/gm
,
''
)
,
title
:
m
.
title
,
reference
:
m
.
reference
,
reference
:
m
.
reference
,
search
:
`
${
m
.
id
}
${
m
.
title
}
`
,
search
:
`
${
m
.
id
}
${
m
.
title
}
`
,
};
};
...
...
spec/frontend/gfm_auto_complete_spec.js
View file @
bd9bc17a
...
@@ -574,6 +574,15 @@ describe('GfmAutoComplete', () => {
...
@@ -574,6 +574,15 @@ describe('GfmAutoComplete', () => {
}),
}),
).
toBe
(
'
<li><small>grp/proj#5</small> Some Issue</li>
'
);
).
toBe
(
'
<li><small>grp/proj#5</small> Some Issue</li>
'
);
});
});
it
(
'
escapes title in the template as it is user input
'
,
()
=>
{
expect
(
GfmAutoComplete
.
Issues
.
templateFunction
({
id
:
5
,
title
:
'
${search}<script>oh no $
'
,
// eslint-disable-line no-template-curly-in-string
}),
).
toBe
(
'
<li><small>5</small> ${search}<script>oh no $</li>
'
);
});
});
});
describe
(
'
GfmAutoComplete.Members
'
,
()
=>
{
describe
(
'
GfmAutoComplete.Members
'
,
()
=>
{
...
@@ -608,16 +617,18 @@ describe('GfmAutoComplete', () => {
...
@@ -608,16 +617,18 @@ describe('GfmAutoComplete', () => {
).
toBe
(
'
<li>IMG my-group <small></small> <i class="icon"/></li>
'
);
).
toBe
(
'
<li>IMG my-group <small></small> <i class="icon"/></li>
'
);
});
});
it
(
'
should add escaped title if title is se
t
'
,
()
=>
{
it
(
'
escapes title in the template as it is user inpu
t
'
,
()
=>
{
expect
(
expect
(
GfmAutoComplete
.
Members
.
templateFunction
({
GfmAutoComplete
.
Members
.
templateFunction
({
avatarTag
:
'
IMG
'
,
avatarTag
:
'
IMG
'
,
username
:
'
my-group
'
,
username
:
'
my-group
'
,
title
:
'
MyGroup+
'
,
title
:
'
${search}<script>oh no $
'
,
// eslint-disable-line no-template-curly-in-string
icon
:
'
<i class="icon"/>
'
,
icon
:
'
<i class="icon"/>
'
,
availabilityStatus
:
''
,
availabilityStatus
:
''
,
}),
}),
).
toBe
(
'
<li>IMG my-group <small>MyGroup+</small> <i class="icon"/></li>
'
);
).
toBe
(
'
<li>IMG my-group <small>${search}<script>oh no $</small> <i class="icon"/></li>
'
,
);
});
});
it
(
'
should add user availability status if availabilityStatus is set
'
,
()
=>
{
it
(
'
should add user availability status if availabilityStatus is set
'
,
()
=>
{
...
@@ -782,6 +793,15 @@ describe('GfmAutoComplete', () => {
...
@@ -782,6 +793,15 @@ describe('GfmAutoComplete', () => {
${
'
/unlabel ~
'
}
|
${
assignedLabels
}
${
'
/unlabel ~
'
}
|
${
assignedLabels
}
`
(
'
$input shows $output.length labels
'
,
expectLabels
);
`
(
'
$input shows $output.length labels
'
,
expectLabels
);
});
});
it
(
'
escapes title in the template as it is user input
'
,
()
=>
{
const
color
=
'
#123456
'
;
const
title
=
'
${search}<script>oh no $
'
;
// eslint-disable-line no-template-curly-in-string
expect
(
GfmAutoComplete
.
Labels
.
templateFunction
(
color
,
title
)).
toBe
(
'
<li><span class="dropdown-label-box" style="background: #123456"></span> ${search}<script>oh no $</li>
'
,
);
});
});
});
describe
(
'
emoji
'
,
()
=>
{
describe
(
'
emoji
'
,
()
=>
{
...
@@ -829,4 +849,15 @@ describe('GfmAutoComplete', () => {
...
@@ -829,4 +849,15 @@ describe('GfmAutoComplete', () => {
});
});
});
});
});
});
describe
(
'
milestones
'
,
()
=>
{
it
(
'
escapes title in the template as it is user input
'
,
()
=>
{
const
expired
=
false
;
const
title
=
'
${search}<script>oh no $
'
;
// eslint-disable-line no-template-curly-in-string
expect
(
GfmAutoComplete
.
Milestones
.
templateFunction
(
title
,
expired
)).
toBe
(
'
<li>${search}<script>oh no $</li>
'
,
);
});
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment