Program: CWE-79
Project: CVE-2021-25977
Buggy source:
Vue.component("pagecopy-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }">\n    <div class="sitemap-item expanded">\n        <div class="link" :class="{ readonly: item.isCopy }">\n            <a v-if="!item.isCopy" :href="piranha.baseUrl + \'manager/page/copyrelative/\' + item.id + \'/\' + piranha.pagelist.addPageId + \'/\' + piranha.pagelist.addAfter">\n                {{ item.title }}\n            </a>\n            <a href="#" v-else>\n                {{ item.title }}\n                <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n            </a>\n            <div class="content-blocker"></div>\n        </div>\n        <div class="type d-none d-md-block">\n            {{ item.typeName }}\n        </div>\n    </div>\n    <ol class="dd-list" v-if="item.items.length > 0">\n        <pagecopy-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child"></pagecopy-item>\n    </ol>\n</li>\n'}),Vue.component("sitemap-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }" :data-id="item.id">\n    <div class="sitemap-item" :class="{ dimmed: item.isUnpublished || item.isScheduled }">\n        <div class="handle dd-handle"><i class="fas fa-ellipsis-v"></i></div>\n        <div class="link">\n            <span class="actions">\n                <a v-if="item.items.length > 0 && item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-minus"></i></a>\n                <a v-if="item.items.length > 0 && !item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-plus"></i></a>\n            </span>\n            <a v-if="piranha.permissions.pages.edit" :href="piranha.baseUrl + item.editUrl + item.id">\n                <span v-html="item.title"></span>\n                <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n                <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n                <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n                <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n            </a>\n            <span v-else class="title">\n                <span v-html="item.title"></span>\n                <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n                <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n                <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n                <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n            </span>\n        </div>\n        <div class="type d-none d-md-block">{{ item.typeName }}</div>\n        <div class="date d-none d-lg-block">{{ item.published }}</div>\n        <div class="actions">\n            <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, true)"><i class="fas fa-angle-down"></i></a>\n            <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, false)"><i class="fas fa-angle-right"></i></a>\n            <a v-if="piranha.permissions.pages.delete && item.items.length === 0" v-on:click.prevent="piranha.pagelist.remove(item.id)" class="danger" href="#"><i class="fas fa-trash"></i></a>\n        </div>\n    </div>\n    <ol v-if="item.items.length > 0" class="dd-list">\n        <sitemap-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child">\n        </sitemap-item>\n    </ol>\n</li>\n'}),piranha.pagelist=new Vue({el:"#pagelist",data:{loading:!0,updateBindings:!1,items:[],sites:[],pageTypes:[],addSiteId:null,addSiteTitle:null,addPageId:null,addAfter:!0},methods:{load:function(){var e=this;piranha.permissions.load(function(){fetch(piranha.baseUrl+"manager/api/page/list").then(function(e){return e.json()}).then(function(i){e.sites=i.sites,e.pageTypes=i.pageTypes,e.updateBindings=!0}).catch(function(e){console.log("error:",e)})})},remove:function(e){var i=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/page/delete/"+e).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),i.load()}).catch(function(e){console.log("error:",e)})}})},bind:function(){var e=this;$(".sitemap-container").each(function(i,s){$(s).nestable({maxDepth:100,group:i,callback:function(i,s){fetch(piranha.baseUrl+"manager/api/page/move",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:$(s).attr("data-id"),items:$(i).nestable("serialize")})}).then(function(e){return e.json()}).then(function(i){piranha.notifications.push(i.status),"success"===i.status.type&&($(".sitemap-container").nestable("destroy"),e.sites=[],Vue.nextTick(function(){e.sites=i.sites,Vue.nextTick(function(){e.bind()})}))}).catch(function(e){console.log("error:",e)})}})})},add:function(e,i,s){var a=this;a.addSiteId=e,a.addPageId=i,a.addAfter=s,a.sites.forEach(function(i){i.id===e&&(a.addSiteTitle=i.title)}),$("#pageAddModal").modal("show")},selectSite:function(e){var i=this;i.addSiteId=e,i.sites.forEach(function(s){s.id===e&&(i.addSiteTitle=s.title)})},collapse:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!1)},expand:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!0)},changeVisibility:function(e,i){e.isExpanded=i;for(var s=0;s<e.items.length;s++)this.changeVisibility(e.items[s],i)}},created:function(){},updated:function(){this.updateBindings&&(this.bind(),this.updateBindings=!1),this.loading=!1}});

Fixed version (ground truth):
Vue.component("pagecopy-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }">\n    <div class="sitemap-item expanded">\n        <div class="link" :class="{ readonly: item.isCopy }">\n            <a v-if="!item.isCopy" :href="piranha.baseUrl + \'manager/page/copyrelative/\' + item.id + \'/\' + piranha.pagelist.addPageId + \'/\' + piranha.pagelist.addAfter">\n                {{ item.title }}\n            </a>\n            <a href="#" v-else>\n                {{ item.title }}\n                <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n            </a>\n            <div class="content-blocker"></div>\n        </div>\n        <div class="type d-none d-md-block">\n            {{ item.typeName }}\n        </div>\n    </div>\n    <ol class="dd-list" v-if="item.items.length > 0">\n        <pagecopy-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child"></pagecopy-item>\n    </ol>\n</li>\n'}),Vue.component("sitemap-item",{props:["item"],methods:{toggleItem:function(e){e.isExpanded=!e.isExpanded}},template:'\n<li class="dd-item" :class="{ expanded: item.isExpanded || item.items.length === 0 }" :data-id="item.id">\n    <div class="sitemap-item" :class="{ dimmed: item.isUnpublished || item.isScheduled }">\n        <div class="handle dd-handle"><i class="fas fa-ellipsis-v"></i></div>\n        <div class="link">\n            <span class="actions">\n                <a v-if="item.items.length > 0 && item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-minus"></i></a>\n                <a v-if="item.items.length > 0 && !item.isExpanded" v-on:click.prevent="toggleItem(item)" class="expand" href="#"><i class="fas fa-plus"></i></a>\n            </span>\n            <a v-if="piranha.permissions.pages.edit" :href="piranha.baseUrl + item.editUrl + item.id">\n                <span>{{ item.title }}</span>\n                <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n                <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n                <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n                <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n            </a>\n            <span v-else class="title">\n                <span>{{ item.title }}</span>\n                <span v-if="item.isRestricted" class="icon-restricted text-secondary small"><i class="fas fa-lock"></i></span>\n                <span v-if="item.status" class="badge badge-info">{{ item.status }}</span>\n                <span v-if="item.isScheduled" class="badge badge-info">{{ piranha.resources.texts.scheduled }}</span>\n                <span v-if="item.isCopy" class="badge badge-warning">{{ piranha.resources.texts.copy }}</span>\n            </span>\n        </div>\n        <div class="type d-none d-md-block">{{ item.typeName }}</div>\n        <div class="date d-none d-lg-block">{{ item.published }}</div>\n        <div class="actions">\n            <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, true)"><i class="fas fa-angle-down"></i></a>\n            <a v-if="piranha.permissions.pages.add" href="#" v-on:click.prevent="piranha.pagelist.add(item.siteId, item.id, false)"><i class="fas fa-angle-right"></i></a>\n            <a v-if="piranha.permissions.pages.delete && item.items.length === 0" v-on:click.prevent="piranha.pagelist.remove(item.id)" class="danger" href="#"><i class="fas fa-trash"></i></a>\n        </div>\n    </div>\n    <ol v-if="item.items.length > 0" class="dd-list">\n        <sitemap-item v-for="child in item.items" v-bind:key="child.id" v-bind:item="child">\n        </sitemap-item>\n    </ol>\n</li>\n'}),piranha.pagelist=new Vue({el:"#pagelist",data:{loading:!0,updateBindings:!1,items:[],sites:[],pageTypes:[],addSiteId:null,addSiteTitle:null,addPageId:null,addAfter:!0},methods:{load:function(){var e=this;piranha.permissions.load(function(){fetch(piranha.baseUrl+"manager/api/page/list").then(function(e){return e.json()}).then(function(i){e.sites=i.sites,e.pageTypes=i.pageTypes,e.updateBindings=!0}).catch(function(e){console.log("error:",e)})})},remove:function(e){var i=this;piranha.alert.open({title:piranha.resources.texts.delete,body:piranha.resources.texts.deletePageConfirm,confirmCss:"btn-danger",confirmIcon:"fas fa-trash",confirmText:piranha.resources.texts.delete,onConfirm:function(){fetch(piranha.baseUrl+"manager/api/page/delete/"+e).then(function(e){return e.json()}).then(function(e){piranha.notifications.push(e),i.load()}).catch(function(e){console.log("error:",e)})}})},bind:function(){var e=this;$(".sitemap-container").each(function(i,s){$(s).nestable({maxDepth:100,group:i,callback:function(i,s){fetch(piranha.baseUrl+"manager/api/page/move",{method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:$(s).attr("data-id"),items:$(i).nestable("serialize")})}).then(function(e){return e.json()}).then(function(i){piranha.notifications.push(i.status),"success"===i.status.type&&($(".sitemap-container").nestable("destroy"),e.sites=[],Vue.nextTick(function(){e.sites=i.sites,Vue.nextTick(function(){e.bind()})}))}).catch(function(e){console.log("error:",e)})}})})},add:function(e,i,s){var a=this;a.addSiteId=e,a.addPageId=i,a.addAfter=s,a.sites.forEach(function(i){i.id===e&&(a.addSiteTitle=i.title)}),$("#pageAddModal").modal("show")},selectSite:function(e){var i=this;i.addSiteId=e,i.sites.forEach(function(s){s.id===e&&(i.addSiteTitle=s.title)})},collapse:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!1)},expand:function(){for(var e=0;e<this.sites.length;e++)for(var i=0;i<this.sites[e].pages.length;i++)this.changeVisibility(this.sites[e].pages[i],!0)},changeVisibility:function(e,i){e.isExpanded=i;for(var s=0;s<e.items.length;s++)this.changeVisibility(e.items[s],i)}},created:function(){},updated:function(){this.updateBindings&&(this.bind(),this.updateBindings=!1),this.loading=!1}});